Tg port 2 15 (#230)

* defines/helpers

* globalvars, onclick, controllers

* datums and game

* woooooooooorld. Uh. dm

* modules sans mobs client admin

* modules/admin

* pref shit

* modules/mob

* icon updates

* extra things

* Cherrypicked fixes from open PRs

* metastation.tgm fix

* a better meta fix

* reverts async breakings
This commit is contained in:
Poojawa
2017-02-15 03:35:32 -06:00
committed by GitHub
parent fd3923d684
commit fc2dbcd9fe
192 changed files with 10451 additions and 160669 deletions

View File

@@ -62,7 +62,7 @@
var/ckeytext = ckey(key)
if(!establish_db_connection())
world.log << "Ban database connection failure. Key [ckeytext] not checked"
log_world("Ban database connection failure. Key [ckeytext] not checked")
diary << "Ban database connection failure. Key [ckeytext] not checked"
return

View File

@@ -129,7 +129,7 @@ var/list/admin_ranks = list() //list of all admin_rank datums
else
establish_db_connection()
if(!dbcon.IsConnected())
world.log << "Failed to connect to database in load_admin_ranks(). Reverting to legacy system."
log_world("Failed to connect to database in load_admin_ranks(). Reverting to legacy system.")
diary << "Failed to connect to database in load_admin_ranks(). Reverting to legacy system."
config.admin_legacy_system = 1
load_admin_ranks()
@@ -204,7 +204,7 @@ var/list/admin_ranks = list() //list of all admin_rank datums
else
establish_db_connection()
if(!dbcon.IsConnected())
world.log << "Failed to connect to database in load_admins(). Reverting to legacy system."
log_world("Failed to connect to database in load_admins(). Reverting to legacy system.")
diary << "Failed to connect to database in load_admins(). Reverting to legacy system."
config.admin_legacy_system = 1
load_admins()

View File

@@ -163,7 +163,8 @@ var/list/admin_verbs_debug = list(
/client/proc/map_template_upload,
/client/proc/jump_to_ruin,
/client/proc/clear_dynamic_transit,
/client/proc/toggle_medal_disable
/client/proc/toggle_medal_disable,
/client/proc/view_runtimes
)
var/list/admin_verbs_possess = list(
/proc/possess,

View File

@@ -346,6 +346,7 @@
var/living_players = 0
var/living_players_connected = 0
var/living_players_antagonist = 0
var/brains = 0
var/other_players = 0
for(var/mob/M in mob_list)
if(M.ckey)
@@ -362,11 +363,13 @@
observers++
if(M.client)
observers_connected++
else if(isbrain(M))
brains++
else
other_players++
dat += "<BR><b><font color='blue' size='3'>Players:|[connected_players - lobby_players] ingame|[connected_players] connected|[lobby_players] lobby|</font></b>"
dat += "<BR><b><font color='green'>Living Players:|[living_players_connected] active|[living_players - living_players_connected] disconnected|[living_players_antagonist] antagonists|</font></b>"
dat += "<BR><b><font color='red'>Dead/Observing players:|[observers_connected] active|[observers - observers_connected] disconnected|</font></b>"
dat += "<BR><b><font color='red'>Dead/Observing players:|[observers_connected] active|[observers - observers_connected] disconnected|[brains] brains|</font></b>"
if(other_players)
dat += "<BR><span class='userdanger'>[other_players] players in invalid state or the statistics code is bugged!</span>"
dat += "<BR>"

View File

@@ -2291,6 +2291,17 @@
ticker.mode.station_goals += G
modify_goals()
else if(href_list["viewruntime"])
var/datum/error_viewer/error_viewer = locate(href_list["viewruntime"])
if(!istype(error_viewer))
usr << "<span class='warning'>That runtime viewer no longer exists.</span>"
return
if(href_list["viewruntime_backto"])
error_viewer.show_to(owner, locate(href_list["viewruntime_backto"]), href_list["viewruntime_linear"])
else
error_viewer.show_to(owner, null, href_list["viewruntime_linear"])
else if(href_list["mentormemoeditlist"])
var/sql_key = sanitizeSQL("[href_list["memoeditlist"]]")
var/DBQuery/query_memoedits = dbcon.NewQuery("SELECT edits FROM [format_table_name("mentor_memo")] WHERE (ckey = '[sql_key]')")

View File

@@ -758,4 +758,14 @@ var/list/TYPES_SHORTCUTS = list(
message_admins("<span class='adminnotice'>[key_name_admin(src)] [global.medals_enabled ? "disabled" : "enabled"] the medal hub lockout.</span>")
feedback_add_details("admin_verb","TMH") // If...
log_admin("[key_name(src)] [global.medals_enabled ? "disabled" : "enabled"] the medal hub lockout.")
log_admin("[key_name(src)] [global.medals_enabled ? "disabled" : "enabled"] the medal hub lockout.")
/client/proc/view_runtimes()
set category = "Debug"
set name = "View Runtimes"
set desc = "Open the runtime Viewer"
if(!holder)
return
error_cache.show_to(src)

View File

@@ -193,7 +193,7 @@
if (rejected)
src << "[rejected] out of [count] objects rejected your edit"
world.log << "### MassVarEdit by [src]: [O.type] (A/R [accepted]/[rejected]) [variable]=[html_encode("[O.vars[variable]]")]([list2params(value)])"
log_world("### MassVarEdit by [src]: [O.type] (A/R [accepted]/[rejected]) [variable]=[html_encode("[O.vars[variable]]")]([list2params(value)])")
log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")

View File

@@ -337,7 +337,7 @@ var/list/VVpixelmovement = list("step_x", "step_y", "bound_height", "bound_width
if (O.vv_edit_var(objectvar, L) == FALSE)
src << "Your edit was rejected by the object."
return
world.log << "### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: ADDED=[var_value]"
log_world("### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: ADDED=[var_value]")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]")
message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: ADDED=[var_value]")
@@ -380,7 +380,7 @@ var/list/VVpixelmovement = list("step_x", "step_y", "bound_height", "bound_width
if (!O.vv_edit_var(objectvar, L))
src << "Your edit was rejected by the object."
return
world.log << "### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR NULLS"
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR NULLS")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: CLEAR NULLS")
message_admins("[key_name_admin(src)] modified [original_name]'s list [objectvar]: CLEAR NULLS")
return
@@ -390,7 +390,7 @@ var/list/VVpixelmovement = list("step_x", "step_y", "bound_height", "bound_width
if (!O.vv_edit_var(objectvar, L))
src << "Your edit was rejected by the object."
return
world.log << "### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR DUPES"
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: CLEAR DUPES")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: CLEAR DUPES")
message_admins("[key_name_admin(src)] modified [original_name]'s list [objectvar]: CLEAR DUPES")
return
@@ -400,7 +400,7 @@ var/list/VVpixelmovement = list("step_x", "step_y", "bound_height", "bound_width
if (!O.vv_edit_var(objectvar, L))
src << "Your edit was rejected by the object."
return
world.log << "### ListVarEdit by [src]: [O.type] [objectvar]: SHUFFLE"
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: SHUFFLE")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: SHUFFLE")
message_admins("[key_name_admin(src)] modified [original_name]'s list [objectvar]: SHUFFLE")
return
@@ -477,7 +477,7 @@ var/list/VVpixelmovement = list("step_x", "step_y", "bound_height", "bound_width
if (O.vv_edit_var(objectvar, L))
src << "Your edit was rejected by the object."
return
world.log << "### ListVarEdit by [src]: [O.type] [objectvar]: REMOVED=[html_encode("[original_var]")]"
log_world("### ListVarEdit by [src]: [O.type] [objectvar]: REMOVED=[html_encode("[original_var]")]")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: REMOVED=[original_var]")
message_admins("[key_name_admin(src)] modified [original_name]'s [objectvar]: REMOVED=[original_var]")
return
@@ -496,7 +496,7 @@ var/list/VVpixelmovement = list("step_x", "step_y", "bound_height", "bound_width
if (O.vv_edit_var(objectvar, L) == FALSE)
src << "Your edit was rejected by the object."
return
world.log << "### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: [original_var]=[new_var]"
log_world("### ListVarEdit by [src]: [(O ? O.type : "/list")] [objectvar]: [original_var]=[new_var]")
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: [original_var]=[new_var]")
message_admins("[key_name_admin(src)] modified [original_name]'s varlist [objectvar]: [original_var]=[new_var]")
@@ -605,6 +605,6 @@ var/list/VVpixelmovement = list("step_x", "step_y", "bound_height", "bound_width
if (O.vv_edit_var(variable, var_new) == FALSE)
src << "Your edit was rejected by the object."
return
world.log << "### VarEdit by [src]: [O.type] [variable]=[html_encode("[O.vars[variable]]")]"
log_world("### VarEdit by [src]: [O.type] [variable]=[html_encode("[O.vars[variable]]")]")
log_admin("[key_name(src)] modified [original_name]'s [variable] to [O.vars[variable]]")
message_admins("[key_name_admin(src)] modified [original_name]'s [variable] to [O.vars[variable]]")

View File

@@ -508,7 +508,11 @@ Traitors and the like can also be revived with the previous role mostly intact.
log_admin("[key_name(usr)] deleted [O] at ([O.x],[O.y],[O.z])")
message_admins("[key_name_admin(usr)] deleted [O] at ([O.x],[O.y],[O.z])")
feedback_add_details("admin_verb","DEL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
qdel(O)
if(isturf(O))
var/turf/T = O
T.ChangeTurf(T.baseturf)
else
qdel(O)
/client/proc/cmd_admin_list_open_jobs()
set category = "Admin"

View File

@@ -93,7 +93,7 @@
M.temporarilyRemoveItemFromInventory(src, TRUE) //Remove the tank from your character,in case you were holding it
if(!M.put_in_hands(R)) //Equips the bomb if possible, or puts it on the floor.
forceMove(M.loc)
forceMove(get_turf(M))
R.bombassembly = S //Tell the bomb about its assembly part
S.master = R //Tell the assembly about its new owner

View File

@@ -37,17 +37,11 @@
create(ckey = user.ckey)
/obj/effect/mob_spawn/Initialize(mapload)
if(roundstart && (mapload || (ticker && ticker.current_state > GAME_STATE_SETTING_UP)))
if(instant || (roundstart && (mapload || (ticker && ticker.current_state > GAME_STATE_SETTING_UP))))
create()
else
poi_list |= src
/obj/effect/mob_spawn/New()
..()
if(instant)
create()
/obj/effect/mob_spawn/Destroy()
poi_list.Remove(src)
. = ..()
@@ -483,4 +477,4 @@
if(despawn == "No" || !loc || !Adjacent(user))
return
user.visible_message("<span class='notice'>[user.name] climbs back into cryosleep...</span>")
qdel(user)
qdel(user)

View File

@@ -586,7 +586,7 @@ var/swapmaps_byname
else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[template_id].txt"))
text=1
else
world.log << "SwapMaps error in SwapMaps_CreateFromTemplate(): map_[template_id] file not found."
log_world("SwapMaps error in SwapMaps_CreateFromTemplate(): map_[template_id] file not found.")
return
if(text)
S=new
@@ -613,7 +613,7 @@ var/swapmaps_byname
else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[chunk_id].txt"))
text=1
else
world.log << "SwapMaps error in SwapMaps_LoadChunk(): map_[chunk_id] file not found."
log_world("SwapMaps error in SwapMaps_LoadChunk(): map_[chunk_id] file not found.")
return
if(text)
S=new
@@ -631,9 +631,11 @@ var/swapmaps_byname
/proc/SwapMaps_SaveChunk(chunk_id,turf/corner1,turf/corner2)
if(!corner1 || !corner2)
world.log << "SwapMaps error in SwapMaps_SaveChunk():"
if(!corner1) world.log << " corner1 turf is null"
if(!corner2) world.log << " corner2 turf is null"
log_world("SwapMaps error in SwapMaps_SaveChunk():")
if(!corner1)
log_world(" corner1 turf is null")
if(!corner2)
log_world(" corner2 turf is null")
return
var/swapmap/M=new
M.id=chunk_id
@@ -660,7 +662,7 @@ var/swapmaps_byname
else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[id].txt"))
text=1
else
world.log << "SwapMaps error in SwapMaps_GetSize(): map_[id] file not found."
log_world("SwapMaps error in SwapMaps_GetSize(): map_[id] file not found.")
return
if(text)
S=new

View File

@@ -18,7 +18,7 @@ var/global/list/potentialRandomZlevels = generateMapList(filename = "config/away
maploader.load_map(file)
smooth_zlevel(world.maxz)
SortAreas()
world.log << "loaded [file] as z-level [world.maxz]"
log_world("loaded [file] as z-level [world.maxz]")
/proc/reset_gateway_spawns(reset = FALSE)
for(var/obj/machinery/gateway/G in world)
@@ -92,7 +92,7 @@ var/global/list/potentialRandomZlevels = generateMapList(filename = "config/away
if(ruins && ruins.len)
ruin = ruins[pick(ruins)]
else
world.log << "Ruin loader had no ruins to pick from with [budget] left to spend."
log_world("Ruin loader had no ruins to pick from with [budget] left to spend.")
break
// Can we afford it
if(ruin.cost > budget)
@@ -119,7 +119,7 @@ var/global/list/potentialRandomZlevels = generateMapList(filename = "config/away
if(!valid)
continue
world.log << "Ruin \"[ruin.name]\" placed at ([T.x], [T.y], [T.z])"
log_world("Ruin \"[ruin.name]\" placed at ([T.x], [T.y], [T.z])")
var/obj/effect/ruin_loader/R = new /obj/effect/ruin_loader(T)
R.Load(ruins,ruin)
@@ -129,7 +129,7 @@ var/global/list/potentialRandomZlevels = generateMapList(filename = "config/away
break
if(!overall_sanity)
world.log << "Ruin loader gave up with [budget] left to spend."
log_world("Ruin loader gave up with [budget] left to spend.")
/obj/effect/ruin_loader

View File

@@ -31,6 +31,7 @@ var/list/preferences_datums = list()
var/hotkeys = FALSE
var/tgui_fancy = TRUE
var/tgui_lock = TRUE
var/windowflashing = TRUE
var/toggles = TOGGLES_DEFAULT
var/chat_toggles = TOGGLES_DEFAULT_CHAT
var/ghost_form = "ghost"
@@ -66,7 +67,6 @@ var/list/preferences_datums = list()
var/list/custom_names = list("clown", "mime", "ai", "cyborg", "religion", "deity")
var/prefered_security_department = SEC_DEPT_RANDOM
var/uplink_spawn_loc = UPLINK_PDA
//Mob preview
var/icon/preview_icon = null
@@ -106,6 +106,8 @@ var/list/preferences_datums = list()
var/parallax = PARALLAX_DISABLE //Starting disabled by default so people stop freaking about about certain issues.
var/uplink_spawn_loc = UPLINK_PDA
/datum/preferences/New(client/C)
parent = C
custom_names["ai"] = pick(ai_names)
@@ -465,6 +467,7 @@ var/list/preferences_datums = list()
dat += "<b>Keybindings:</b> <a href='?_src_=prefs;preference=hotkeys'>[(hotkeys) ? "Hotkeys" : "Default"]</a><br>"
dat += "<b>tgui Style:</b> <a href='?_src_=prefs;preference=tgui_fancy'>[(tgui_fancy) ? "Fancy" : "No Frills"]</a><br>"
dat += "<b>tgui Monitors:</b> <a href='?_src_=prefs;preference=tgui_lock'>[(tgui_lock) ? "Primary" : "All"]</a><br>"
dat += "<b>Window Flashing:</b> <a href='?_src_=prefs;preference=winflash'>[(windowflashing) ? "Yes" : "No"]</a><br>"
dat += "<b>Play admin midis:</b> <a href='?_src_=prefs;preference=hear_midis'>[(toggles & SOUND_MIDI) ? "Yes" : "No"]</a><br>"
dat += "<b>Play lobby music:</b> <a href='?_src_=prefs;preference=lobby_music'>[(toggles & SOUND_LOBBY) ? "Yes" : "No"]</a><br>"
dat += "<b>Ghost ears:</b> <a href='?_src_=prefs;preference=ghost_ears'>[(chat_toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"]</a><br>"
@@ -1358,7 +1361,8 @@ var/list/preferences_datums = list()
tgui_fancy = !tgui_fancy
if("tgui_lock")
tgui_lock = !tgui_lock
if("winflash")
windowflashing = !windowflashing
if("hear_adminhelps")
toggles ^= SOUND_ADMINHELP
if("announce_login")

View File

@@ -153,6 +153,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["hotkeys"] >> hotkeys
S["tgui_fancy"] >> tgui_fancy
S["tgui_lock"] >> tgui_lock
S["windowflash"] >> windowflashing
if(islist(S["be_special"]))
S["be_special"] >> be_special
@@ -174,7 +175,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["uses_glasses_colour"]>> uses_glasses_colour
S["clientfps"] >> clientfps
S["parallax"] >> parallax
S["uplink_loc"] >> uplink_spawn_loc
//citadel code
S["arousable"] >> arousable
@@ -190,6 +190,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
hotkeys = sanitize_integer(hotkeys, 0, 1, initial(hotkeys))
tgui_fancy = sanitize_integer(tgui_fancy, 0, 1, initial(tgui_fancy))
tgui_lock = sanitize_integer(tgui_lock, 0, 1, initial(tgui_lock))
windowflashing = sanitize_integer(windowflashing, 0, 1, initial(windowflashing))
default_slot = sanitize_integer(default_slot, 1, max_save_slots, initial(default_slot))
toggles = sanitize_integer(toggles, 0, 65535, initial(toggles))
clientfps = sanitize_integer(clientfps, 0, 1000, 0)
@@ -218,6 +219,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["hotkeys"] << hotkeys
S["tgui_fancy"] << tgui_fancy
S["tgui_lock"] << tgui_lock
S["windowflash"] << windowflashing
S["be_special"] << be_special
S["default_slot"] << default_slot
S["toggles"] << toggles
@@ -290,6 +292,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["undershirt"] >> undershirt
S["socks"] >> socks
S["backbag"] >> backbag
S["uplink_loc"] >> uplink_spawn_loc
S["feature_mcolor"] >> features["mcolor"]
S["feature_mcolor2"] >> features["mcolor2"]
S["feature_mcolor3"] >> features["mcolor3"]
@@ -372,6 +375,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
eye_color = sanitize_hexcolor(eye_color, 3, 0)
skin_tone = sanitize_inlist(skin_tone, skin_tones)
backbag = sanitize_inlist(backbag, backbaglist, initial(backbag))
uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, uplink_spawn_loc_list, initial(uplink_spawn_loc))
features["mcolor"] = sanitize_hexcolor(features["mcolor"], 3, 0)
features["mcolor2"] = sanitize_hexcolor(features["mcolor2"], 3, 0)
features["mcolor3"] = sanitize_hexcolor(features["mcolor3"], 3, 0)
@@ -393,8 +397,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
features["xenodorsal"] = sanitize_inlist(features["xenodorsal"], xeno_dorsal_list)
features["feature_lizard_legs"] = sanitize_inlist(features["legs"], legs_list, "Normal Legs")
uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, uplink_spawn_loc_list, initial(uplink_spawn_loc))
joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
job_civilian_high = sanitize_integer(job_civilian_high, 0, 65535, initial(job_civilian_high))
job_civilian_med = sanitize_integer(job_civilian_med, 0, 65535, initial(job_civilian_med))
@@ -435,6 +437,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["undershirt"] << undershirt
S["socks"] << socks
S["backbag"] << backbag
S["uplink_loc"] << uplink_spawn_loc
S["flavor_text"] << flavor_text
S["species"] << pref_species.id
S["feature_mcolor"] << features["mcolor"]
@@ -465,8 +468,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["religion_name"] << custom_names["religion"]
S["deity_name"] << custom_names["deity"]
S["prefered_security_department"] << prefered_security_department
S["uplink_loc"] << uplink_spawn_loc
//Jobs
S["joblessrole"] << joblessrole

View File

@@ -46,14 +46,10 @@
if(istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech
return
if(!M.restrained() && !M.stat && loc == M && istype(over_object, /obj/screen/inventory/hand))
if(!M.incapacitated() && loc == M && istype(over_object, /obj/screen/inventory/hand))
var/obj/screen/inventory/hand/H = over_object
if(!M.temporarilyRemoveItemFromInventory(src))
return
if(!M.put_in_hand(src, H.held_index))
qdel(src)
return
add_fingerprint(usr)
if(M.putItemFromInventoryInHandIfPossible(src, H.held_index))
add_fingerprint(usr)
/obj/item/clothing/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
if(pockets)

View File

@@ -15,7 +15,7 @@
/obj/item/clothing/shoes/clown_shoes/banana_shoes/step_action()
if(on)
if(footstep > 1)//honks when its on
playsound(src, "sound/items/bikehorn.ogg", 75, 1)
playsound(src, 'sound/items/bikehorn.ogg', 75, 1)
footstep = 0
else
footstep++

View File

@@ -63,12 +63,12 @@
var/current_time = time_stamp()
if(!fingerprintshidden[M.key])
fingerprintshidden[M.key] = "First: [M.real_name]\[[current_time]\][hasgloves]."
fingerprintshidden[M.key] = "First: [M.real_name]\[[current_time]\][hasgloves]. Ckey: [M.ckey]"
else
var/laststamppos = findtext(fingerprintshidden[M.key], " Last: ")
if(laststamppos)
fingerprintshidden[M.key] = copytext(fingerprintshidden[M.key], 1, laststamppos)
fingerprintshidden[M.key] += " Last: [M.real_name]\[[current_time]\][hasgloves]."
fingerprintshidden[M.key] += " Last: [M.real_name]\[[current_time]\][hasgloves]. Ckey: [M.ckey]"
fingerprintslast = M.ckey

View File

@@ -0,0 +1,114 @@
var/global/list/error_last_seen = list()
var/global/list/error_cooldown = list() /* Error_cooldown items will either be positive(cooldown time) or negative(silenced error)
If negative, starts at -1, and goes down by 1 each time that error gets skipped*/
var/global/total_runtimes = 0
var/global/total_runtimes_skipped = 0
#ifdef DEBUG
/world/Error(exception/E, datum/e_src)
if(!istype(E)) //Something threw an unusual exception
log_world("\[[time_stamp()]] Uncaught exception: [E]")
return ..()
if(!error_last_seen) // A runtime is occurring too early in start-up initialization
return ..()
total_runtimes++
var/erroruid = "[E.file][E.line]"
var/last_seen = error_last_seen[erroruid]
var/cooldown = error_cooldown[erroruid] || 0
if(last_seen == null)
error_last_seen[erroruid] = world.time
last_seen = world.time
if(cooldown < 0)
error_cooldown[erroruid]-- //Used to keep track of skip count for this error
total_runtimes_skipped++
return //Error is currently silenced, skip handling it
//Handle cooldowns and silencing spammy errors
var/silencing = FALSE
// We can runtime before config is initialized because BYOND initialize objs/map before a bunch of other stuff happens.
// This is a bunch of workaround code for that. Hooray!
var/configured_error_cooldown = initial(config.error_cooldown)
var/configured_error_limit = initial(config.error_limit)
var/configured_error_silence_time = initial(config.error_silence_time)
if(config)
configured_error_cooldown = config.error_cooldown
configured_error_limit = config.error_limit
configured_error_silence_time = config.error_silence_time
//Each occurence of an unique error adds to its cooldown time...
cooldown = max(0, cooldown - (world.time - last_seen)) + configured_error_cooldown
// ... which is used to silence an error if it occurs too often, too fast
if(cooldown > configured_error_cooldown * configured_error_limit)
cooldown = -1
silencing = TRUE
spawn(0)
usr = null
sleep(configured_error_silence_time)
var/skipcount = abs(error_cooldown[erroruid]) - 1
error_cooldown[erroruid] = 0
if(skipcount > 0)
world.log << "\[[time_stamp()]] Skipped [skipcount] runtimes in [E.file],[E.line]."
error_cache.log_error(E, skip_count = skipcount)
error_last_seen[erroruid] = world.time
error_cooldown[erroruid] = cooldown
var/list/usrinfo = null
var/locinfo
if(istype(usr))
usrinfo = list(" usr: [datum_info_line(usr)]")
locinfo = atom_loc_line(usr)
if(locinfo)
usrinfo += " usr.loc: [locinfo]"
// The proceeding mess will almost definitely break if error messages are ever changed
var/list/splitlines = splittext(E.desc, "\n")
var/list/desclines = list()
if(LAZYLEN(splitlines) > ERROR_USEFUL_LEN) // If there aren't at least three lines, there's no info
for(var/line in splitlines)
if(LAZYLEN(line) < 3 || findtext(line, "source file:") || findtext(line, "usr.loc:"))
continue
if(findtext(line, "usr:"))
if(usrinfo)
desclines.Add(usrinfo)
usrinfo = null
continue // Our usr info is better, replace it
if(copytext(line, 1, 3) != " ")
desclines += (" " + line) // Pad any unpadded lines, so they look pretty
else
desclines += line
if(usrinfo) //If this info isn't null, it hasn't been added yet
desclines.Add(usrinfo)
if(silencing)
desclines += " (This error will now be silenced for [configured_error_silence_time / 600] minutes)"
if(error_cache)
error_cache.log_error(E, desclines)
world.log << "\[[time_stamp()]] Runtime in [E.file],[E.line]: [E]"
for(var/line in desclines)
world.log << line
/* This logs the runtime in the old format */
E.name = "\n\[[time2text(world.timeofday,"hh:mm:ss")]\][E.name]"
//Original
//
var/list/split = splittext(E.desc, "\n")
for (var/i in 1 to split.len)
if (split[i] != "")
split[i] = "\[[time2text(world.timeofday,"hh:mm:ss")]\][split[i]]"
E.desc = jointext(split, "\n")
if(config && config.log_runtimes)
world.log = runtime_diary
..(E)
world.log = null
#endif

View File

@@ -0,0 +1,194 @@
// Error viewing datums, responsible for storing error info, notifying admins
// when errors occur, and showing them to admins on demand.
// There are 3 different types used here:
//
// - error_cache keeps track of all error sources, as well as all individually
// logged errors. Only one instance of this datum should ever exist, and it's
// right here:
#ifdef DEBUG
/var/datum/error_viewer/error_cache/error_cache = new()
#else
// If debugging is disabled, there's nothing useful to log, so don't bother.
/var/datum/error_viewer/error_cache/error_cache = null
#endif
// - error_source datums exist for each line (of code) that generates an error,
// and keep track of all errors generated by that line.
//
// - error_entry datums exist for each logged error, and keep track of all
// relevant info about that error.
// Common vars and procs are kept at the error_viewer level
/datum/error_viewer
var/name = ""
/datum/error_viewer/proc/browse_to(client/user, html)
var/datum/browser/browser = new(user.mob, "error_viewer", null, 600, 400)
browser.set_content(html)
browser.add_head_content({"
<style>
.runtime
{
background-color: #171717;
border: solid 1px #202020;
font-family: "Courier New";
padding-left: 10px;
color: #CCCCCC;
}
.runtime_line
{
margin-bottom: 10px;
display: inline-block;
}
</style>
"})
browser.open()
/datum/error_viewer/proc/build_header(datum/error_viewer/back_to, linear)
// Common starter HTML for show_to
. = ""
if (istype(back_to))
. += back_to.make_link("<b>&lt;&lt;&lt;</b>", null, linear)
. += "[make_link("Refresh")]<br><br>"
/datum/error_viewer/proc/show_to(user, datum/error_viewer/back_to, linear)
// Specific to each child type
return
/datum/error_viewer/proc/make_link(linktext, datum/error_viewer/back_to, linear)
var/back_to_param = ""
if (!linktext)
linktext = name
if (istype(back_to))
back_to_param = ";viewruntime_backto=\ref[back_to]"
if (linear)
back_to_param += ";viewruntime_linear=1"
return "<a href='?_src_=holder;viewruntime=\ref[src][back_to_param]'>[linktext]</a>"
/datum/error_viewer/error_cache
var/list/errors = list()
var/list/error_sources = list()
var/list/errors_silenced = list()
/datum/error_viewer/error_cache/show_to(user, datum/error_viewer/back_to, linear)
var/html = build_header()
html += "<b>[global.total_runtimes]</b> runtimes, <b>[global.total_runtimes_skipped]</b> skipped<br><br>"
if (!linear)
html += "organized | [make_link("linear", null, 1)]<hr>"
var/datum/error_viewer/error_source/error_source
for (var/erroruid in error_sources)
error_source = error_sources[erroruid]
html += "[error_source.make_link(null, src)]<br>"
else
html += "[make_link("organized", null)] | linear<hr>"
for (var/datum/error_viewer/error_entry/error_entry in errors)
html += "[error_entry.make_link(null, src, 1)]<br>"
browse_to(user, html)
/datum/error_viewer/error_cache/proc/log_error(exception/e, list/desclines, skip_count)
if (!istype(e))
return // Abnormal exception, don't even bother
var/erroruid = "[e.file][e.line]"
var/datum/error_viewer/error_source/error_source = error_sources[erroruid]
if (!error_source)
error_source = new(e)
error_sources[erroruid] = error_source
var/datum/error_viewer/error_entry/error_entry = new(e, desclines, skip_count)
error_entry.error_source = error_source
errors += error_entry
error_source.errors += error_entry
if (skip_count)
return // Skip notifying admins about skipped errors.
// Show the error to admins with debug messages turned on, but only if one
// from the same source hasn't been shown too recently
if (error_source.next_message_at <= world.time)
var/const/viewtext = "\[view]" // Nesting these in other brackets went poorly
//log_debug("Runtime in <b>[e.file]</b>, line <b>[e.line]</b>: <b>[html_encode(e.name)]</b> [error_entry.make_link(viewtext)]")
var/err_msg_delay
if(config)
err_msg_delay = config.error_msg_delay
else
err_msg_delay = initial(config.error_msg_delay)
error_source.next_message_at = world.time + err_msg_delay
/datum/error_viewer/error_source
var/list/errors = list()
var/next_message_at = 0
/datum/error_viewer/error_source/New(exception/e)
if (!istype(e))
name = "\[[time_stamp()]] Uncaught exceptions"
return
name = "<b>\[[time_stamp()]]</b> Runtime in <b>[e.file]</b>, line <b>[e.line]</b>: <b>[html_encode(e.name)]</b>"
/datum/error_viewer/error_source/show_to(user, datum/error_viewer/back_to, linear)
if (!istype(back_to))
back_to = error_cache
var/html = build_header(back_to)
for (var/datum/error_viewer/error_entry/error_entry in errors)
html += "[error_entry.make_link(null, src)]<br>"
browse_to(user, html)
/datum/error_viewer/error_entry
var/datum/error_viewer/error_source/error_source
var/exception/exc
var/desc = ""
var/usr_ref
var/turf/usr_loc
var/is_skip_count
/datum/error_viewer/error_entry/New(exception/e, list/desclines, skip_count)
if (!istype(e))
name = "<b>\[[time_stamp()]]</b> Uncaught exception: <b>[html_encode(e.name)]</b>"
return
if(skip_count)
name = "\[[time_stamp()]] Skipped [skip_count] runtimes in [e.file],[e.line]."
is_skip_count = TRUE
return
name = "<b>\[[time_stamp()]]</b> Runtime in <b>[e.file]</b>, line <b>[e.line]</b>: <b>[html_encode(e.name)]</b>"
exc = e
if (istype(desclines))
for (var/line in desclines)
// There's probably a better way to do this than non-breaking spaces...
desc += "<span class='runtime_line'>[html_encode(line)]</span><br>"
if (usr)
usr_ref = "\ref[usr]"
usr_loc = get_turf(usr)
/datum/error_viewer/error_entry/show_to(user, datum/error_viewer/back_to, linear)
if (!istype(back_to))
back_to = error_source
var/html = build_header(back_to, linear)
html += "[name]<div class='runtime'>[desc]</div>"
if (usr_ref)
html += "<br><b>usr</b>: <a href='?_src_=vars;Vars=[usr_ref]'>VV</a>"
html += " <a href='?_src_=holder;adminplayeropts=[usr_ref]'>PP</a>"
html += " <a href='?_src_=holder;adminplayerobservefollow=[usr_ref]'>Follow</a>"
if (istype(usr_loc))
html += "<br><b>usr.loc</b>: <a href='?_src_=vars;Vars=\ref[usr_loc]'>VV</a>"
html += " <a href='?_src_=holder;adminplayerobservecoodjump=1;X=[usr_loc.x];Y=[usr_loc.y];Z=[usr_loc.z]'>JMP</a>"
browse_to(user, html)
/datum/error_viewer/error_entry/make_link(linktext, datum/error_viewer/back_to, linear)
return is_skip_count ? name : ..()

View File

@@ -86,7 +86,7 @@
"You're hotter than a plasma fire in toxins.",
"Are you a rogue atmos tech? Because you're taking my breath away.",
"Could I have all access... to your heart?",
"Call me the CMO, because I'm here to inspect your johnson.",
"Call me the doctor, because I'm here to inspect your johnson.",
"I'm not a changeling, but you make my proboscis extend.",
"I just can't get EI NATH of you.",
"You must be a nuke op, because you make my heart explode.",
@@ -116,7 +116,15 @@
"Roses are red, text is green, I love you more than cleanbots clean.",
"If you were a carp I'd fi-lay you.",
"I'm a nuke op, and my pinpointer leads to your heart.",
"Wanna slay my megafauna?" )
"Wanna slay my megafauna?",
"I'm a clockwork cultist. Or zl inyragvar.",
"If you were a disposal bin I'd ride you all day.",
"Put on your explorer's suit because I'm taking you to LOVEaland.",
"I must be the CMO, 'cause I saw you on my CUTE sensors.",
"You're the vomit to my flyperson.",
"You must be liquid dark matter, because you're pulling me closer.",
"Not even sorium can drive me away from you.",
"Wanna make like a borg and do some heavy petting?" )
/obj/item/weapon/valentine/attackby(obj/item/weapon/W, mob/user, params)
..()
@@ -167,5 +175,7 @@
"A heart-shaped candy that reads: VALIDTINES",
"A heart-shaped candy that reads: FACEHUGGER",
"A heart-shaped candy that reads: DOMINATOR",
"A heart-shaped candy that reads: GET TESLA'D")
"A heart-shaped candy that reads: GET TESLA'D",
"A heart-shaped candy that reads: COCK CULT",
"A heart-shaped candy that reads: PET ME")
icon_state = pick("candyheart", "candyheart2", "candyheart3", "candyheart4")

View File

@@ -33,7 +33,7 @@
if(areasToOpen && areasToOpen.len > 0)
priority_announce("Gr3y.T1d3 virus detected in [station_name()] door subroutines. Severity level of [severity]. Recommend station AI involvement.", "Security Alert")
else
world.log << "ERROR: Could not initate grey-tide. No areas in the list!"
log_world("ERROR: Could not initate grey-tide. No areas in the list!")
kill()

View File

@@ -637,16 +637,21 @@
desc = "A shot glass - the universal symbol for bad decisions."
return
// for /obj/machinery/vending/sovietsoda
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/filled/New()
..()
on_reagent_change()
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/filled/soda
name = "Soda Water"
list_reagents = list("sodawater" = 50)
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/filled/cola
name = "Space Cola"
list_reagents = list("cola" = 50)
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/filled/nuka_cola
name = "Nuka Cola"
list_reagents = list("nuka_cola" = 50)
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/attackby(obj/item/I, mob/user, params)
if(istype(I,/obj/item/weapon/reagent_containers/food/snacks/egg)) //breaking eggs

View File

@@ -77,7 +77,7 @@ insert ascii eagle on american flag background here
if(frying)
cook_time++
if(cook_time == 30)
playsound(src.loc, "sound/machines/ding.ogg", 50, 1)
playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
visible_message("[src] dings!")
else if (cook_time == 60)
visible_message("[src] emits an acrid smell!")
@@ -133,4 +133,4 @@ insert ascii eagle on american flag background here
reagents.remove_any((reagents.total_volume/2))
C.Weaken(3)
user.changeNext_move(CLICK_CD_MELEE)
..()
..()

View File

@@ -399,7 +399,7 @@
desc = "A refrigerated storage unit for medicine storage."
var/list/spawn_meds = list(
/obj/item/weapon/reagent_containers/pill/epinephrine = 12,
/obj/item/weapon/reagent_containers/pill/charcoal = 1,
/obj/item/weapon/reagent_containers/pill/charcoal = 5,
/obj/item/weapon/reagent_containers/glass/bottle/epinephrine = 1,
/obj/item/weapon/reagent_containers/glass/bottle/charcoal = 1)

View File

@@ -54,9 +54,9 @@
// the following is necessary for power reasons
var/area/AS = get_area(src)
if(istype(AS,/area/holodeck))
world.log << "### MAPPING ERROR"
world.log << "Holodeck computer cannot be in a holodeck."
world.log << "This would cause circular power dependency."
log_world("### MAPPING ERROR")
log_world("Holodeck computer cannot be in a holodeck.")
log_world("This would cause circular power dependency.")
qdel(src) // todo handle constructed computers
return //l-lewd...
else
@@ -194,6 +194,7 @@
/obj/machinery/computer/holodeck/Destroy()
emergency_shutdown()
linked.linked = null
return ..()
/obj/machinery/computer/holodeck/emp_act(severity)

View File

@@ -35,11 +35,14 @@ Clown
/obj/item/weapon/reagent_containers/food/drinks/soda_cans/canned_laughter = 1
)
implants = list(/obj/item/weapon/implant/sad_trombone)
backpack = /obj/item/weapon/storage/backpack/clown
satchel = /obj/item/weapon/storage/backpack/clown
dufflebag = /obj/item/weapon/storage/backpack/dufflebag/clown //strangely has a duffle
implants = list(/obj/item/weapon/implant/sad_trombone)
box = /obj/item/weapon/storage/box/hug/survival
/datum/outfit/job/clown/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
..()

View File

@@ -0,0 +1,271 @@
//Aux base construction console
/mob/camera/aiEye/remote/base_construction
name = "construction holo-drone"
move_on_shuttle = 1 //Allows any curious crew to watch the base after it leaves. (This is safe as the base cannot be modified once it leaves)
icon = 'icons/obj/mining.dmi'
icon_state = "construction_drone"
var/area/starting_area
mob/camera/aiEye/remote/base_construction/New(loc)
starting_area = get_area(loc)
..()
/mob/camera/aiEye/remote/base_construction/setLoc(var/t)
var/area/curr_area = get_area(t)
if(curr_area == starting_area || istype(curr_area, /area/shuttle/auxillary_base))
return ..()
//While players are only allowed to build in the base area, but consoles starting outside the base can move into the base area to begin work.
/mob/camera/aiEye/remote/base_construction/relaymove(mob/user, direct)
dir = direct //This camera eye is visible as a drone, and needs to keep the dir updated
..()
/obj/item/weapon/rcd/internal //Base console's internal RCD. Roundstart consoles are filled, rebuilt cosoles start empty.
name = "internal RCD"
max_matter = 600 //Bigger container and faster speeds due to being specialized and stationary.
no_ammo_message = "<span class='warning'>Internal matter exhausted. Please add additional materials.</span>"
walldelay = 10
grilledelay = 5
windowdelay = 5
airlockdelay = 20
decongirderdelay = 10
deconwalldelay = 20
deconfloordelay = 30
deconwindowdelay = 20
deconairlockdelay = 20
/obj/machinery/computer/camera_advanced/base_construction
name = "base contruction console"
desc = "An industrial computer integrated with a camera-assisted rapid construction device."
networks = list("SS13")
var/obj/item/weapon/rcd/internal/RCD //Internal RCD. The computer passes user commands to this in order to avoid massive copypaste.
circuit = /obj/item/weapon/circuitboard/computer/base_construction
off_action = new/datum/action/innate/camera_off/base_construction
var/datum/action/innate/aux_base/switch_mode/switch_mode_action = new //Action for switching the RCD's build modes
var/datum/action/innate/aux_base/build/build_action = new //Action for using the RCD
var/datum/action/innate/aux_base/airlock_type/airlock_mode_action = new //Action for setting the airlock type
var/datum/action/innate/aux_base/window_type/window_action = new //Action for setting the window type
var/datum/action/innate/aux_base/place_fan/fan_action = new //Action for spawning fans
var/fans_remaining = 0 //Number of fans in stock.
var/datum/action/innate/aux_base/install_turret/turret_action = new //Action for spawning turrets
var/turret_stock = 0 //Turrets in stock
var/obj/machinery/computer/shuttle/auxillary_base/found_aux_console //Tracker for the Aux base console, so the eye can always find it.
icon_screen = "mining"
icon_keyboard = "rd_key"
/obj/machinery/computer/camera_advanced/base_construction/New()
..()
RCD = new /obj/item/weapon/rcd/internal(src)
/obj/machinery/computer/camera_advanced/base_construction/Initialize(mapload)
..()
if(mapload) //Map spawned consoles have a filled RCD and stocked special structures
RCD.matter = RCD.max_matter
fans_remaining = 4
turret_stock = 4
/obj/machinery/computer/camera_advanced/base_construction/CreateEye()
var/spawn_spot
if(!found_aux_console)
found_aux_console = locate(/obj/machinery/computer/shuttle/auxillary_base) in machines
if(found_aux_console)
spawn_spot = found_aux_console
else
spawn_spot = src
eyeobj = new /mob/camera/aiEye/remote/base_construction(get_turf(spawn_spot))
eyeobj.origin = src
/obj/machinery/computer/camera_advanced/base_construction/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/weapon/rcd_ammo) || istype(W, /obj/item/stack/sheet))
RCD.attackby(W, user, params) //If trying to feed the console more materials, pass it along to the RCD.
else
return ..()
/obj/machinery/computer/camera_advanced/base_construction/GrantActions(mob/living/user)
off_action.target = user
off_action.Grant(user)
switch_mode_action.target = src
switch_mode_action.Grant(user)
build_action.target = src
build_action.Grant(user)
airlock_mode_action.target = src
airlock_mode_action.Grant(user)
window_action.target = src
window_action.Grant(user)
fan_action.target = src
fan_action.Grant(user)
turret_action.target = src
turret_action.Grant(user)
eyeobj.invisibility = 0 //When the eye is in use, make it visible to players so they know when someone is building.
/datum/action/innate/aux_base //Parent aux base action
var/mob/living/C //Mob using the action
var/mob/camera/aiEye/remote/base_construction/remote_eye //Console's eye mob
var/obj/machinery/computer/camera_advanced/base_construction/B //Console itself
/datum/action/innate/aux_base/Activate()
if(!target)
return TRUE
C = owner
remote_eye = C.remote_control
B = target
if(!B.RCD) //The console must always have an RCD.
B.RCD = new /obj/item/weapon/rcd/internal(src) //If the RCD is lost somehow, make a new (empty) one!
/datum/action/innate/aux_base/proc/check_spot()
//Check a loction to see if it is inside the aux base at the station. Camera visbility checks omitted so as to not hinder construction.
var/turf/build_target = get_turf(remote_eye)
var/area/build_area = get_area(build_target)
if(!istype(build_area, /area/shuttle/auxillary_base))
owner << "<span class='warning'>You can only build within the mining base!</span>"
return FALSE
if(build_target.z != ZLEVEL_STATION)
owner << "<span class='warning'>The mining base has launched and can no longer be modified.</span>"
return FALSE
return TRUE
/datum/action/innate/camera_off/base_construction
name = "Log out"
/datum/action/innate/camera_off/base_construction/Activate()
if(!owner || !owner.remote_control)
return
var/mob/camera/aiEye/remote/base_construction/remote_eye =owner.remote_control
var/obj/machinery/computer/camera_advanced/base_construction/origin = remote_eye.origin
origin.switch_mode_action.Remove(target)
origin.build_action.Remove(target)
origin.airlock_mode_action.Remove(target)
origin.window_action.Remove(target)
origin.fan_action.Remove(target)
origin.turret_action.Remove(target)
remote_eye.invisibility = INVISIBILITY_MAXIMUM //Hide the eye when not in use.
..()
//*******************FUNCTIONS*******************
/datum/action/innate/aux_base/build
name = "Build"
button_icon_state = "build"
/datum/action/innate/aux_base/build/Activate()
if(..())
return
if(!check_spot())
return
var/atom/movable/rcd_target
var/turf/target_turf = get_turf(remote_eye)
//Find airlocks
rcd_target = locate(/obj/machinery/door/airlock) in target_turf
if(!rcd_target)
rcd_target = locate (/obj/structure) in target_turf
if(!rcd_target || !rcd_target.anchored)
rcd_target = target_turf
owner.changeNext_move(CLICK_CD_RANGE)
B.RCD.afterattack(rcd_target, owner, TRUE) //Activate the RCD and force it to work remotely!
playsound(target_turf, 'sound/items/Deconstruct.ogg', 60, 1)
/datum/action/innate/aux_base/switch_mode
name = "Switch Mode"
button_icon_state = "builder_mode"
/datum/action/innate/aux_base/switch_mode/Activate()
if(..())
return
var/list/buildlist = list("Walls and Floors" = 1,"Airlocks" = 2,"Deconstruction" = 3,"Windows and Grilles" = 4)
var/buildmode = input("Set construction mode.", "Base Console", null) in buildlist
B.RCD.mode = buildlist[buildmode]
owner << "Build mode is now [buildmode]."
/datum/action/innate/aux_base/airlock_type
name = "Select Airlock Type"
button_icon_state = "airlock_select"
datum/action/innate/aux_base/airlock_type/Activate()
if(..())
return
B.RCD.change_airlock_setting()
datum/action/innate/aux_base/window_type
name = "Select Window Type"
button_icon_state = "window_select"
datum/action/innate/aux_base/window_type/Activate()
if(..())
return
B.RCD.toggle_window_type()
datum/action/innate/aux_base/place_fan
name = "Place Tiny Fan"
button_icon_state = "build_fan"
datum/action/innate/aux_base/place_fan/Activate()
if(..())
return
var/turf/fan_turf = get_turf(remote_eye)
if(!B.fans_remaining)
owner << "<span class='warning'>[B] is out of fans!</span>"
return
if(!check_spot())
return
if(fan_turf.density)
owner << "<span class='warning'>Fans may only be placed on a floor.</span>"
return
new /obj/structure/fans/tiny(fan_turf)
B.fans_remaining--
owner << "<span class='notice'>Tiny fan placed. [B.fans_remaining] remaining.</span>"
playsound(fan_turf, 'sound/machines/click.ogg', 50, 1)
datum/action/innate/aux_base/install_turret
name = "Install Plasma Anti-Wildlife Turret"
button_icon_state = "build_turret"
datum/action/innate/aux_base/install_turret/Activate()
if(..())
return
if(!check_spot())
return
if(!B.turret_stock)
owner << "<span class='warning'>Unable to construct additional turrets.</span>"
return
var/turf/turret_turf = get_turf(remote_eye)
if(is_blocked_turf(turret_turf))
owner << "<span class='warning'>Location is obtructed by something. Please clear the location and try again.</span>"
return
new /obj/machinery/porta_turret/aux_base(turret_turf)
B.turret_stock--
owner << "<span class='notice'>Turret installation complete!</span>"
playsound(turret_turf, 'sound/items/drill_use.ogg', 65, 1)

View File

@@ -331,17 +331,13 @@
if (istype(usr.loc,/obj/mecha))
return
if(!M.restrained() && !M.stat)
if(!M.incapacitated())
playsound(loc, "rustle", 50, 1, -5)
if(istype(over_object, /obj/screen/inventory/hand))
var/obj/screen/inventory/hand/H = over_object
if(!M.temporarilyRemoveItemFromInventory(src))
return
if(!M.put_in_hand(src, H.held_index))
qdel(src)
return //fuck these things
M.putItemFromInventoryInHandIfPossible(src, H.held_index)
add_fingerprint(usr)

View File

@@ -299,7 +299,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/Stat()
..()
if(statpanel("Status"))
stat(null, "Station Time: [worldtime2text()]")
if(ticker && ticker.mode)
for(var/datum/gang/G in ticker.mode.gangs)
if(G.is_dominating)
@@ -328,7 +327,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
mind.current.key = key
return 1
/mob/dead/observer/proc/notify_cloning(var/message, var/sound, var/atom/source)
/mob/dead/observer/proc/notify_cloning(var/message, var/sound, var/atom/source, flashwindow = TRUE)
if(flashwindow)
window_flash(client)
if(message)
src << "<span class='ghostalert'>[message]</span>"
if(source)

View File

@@ -148,15 +148,16 @@
/mob/proc/can_equip(obj/item/I, slot, disable_warning = 0)
return FALSE
/mob/proc/put_in_hand(obj/item/I, hand_index)
/mob/proc/can_put_in_hand(I, hand_index)
if(!put_in_hand_check(I))
return FALSE
if(!has_hand_for_held_index(hand_index))
return FALSE
var/obj/item/curr = held_items[hand_index]
if(!curr)
I.loc = src
return !held_items[hand_index]
/mob/proc/put_in_hand(obj/item/I, hand_index)
if(can_put_in_hand(I, hand_index))
I.forceMove(src)
held_items[hand_index] = I
I.layer = ABOVE_HUD_LAYER
I.plane = ABOVE_HUD_PLANE
@@ -255,6 +256,17 @@
return FALSE
return TRUE
/mob/proc/putItemFromInventoryInHandIfPossible(obj/item/I, hand_index, force_removal = FALSE)
if(!can_put_in_hand(I, hand_index))
return FALSE
if(!temporarilyRemoveItemFromInventory(I, force_removal))
return FALSE
I.remove_item_from_storage(src)
if(!put_in_hand(I, hand_index))
qdel(I)
CRASH("Assertion failure: putItemFromInventoryInHandIfPossible") //should never be possible
return TRUE
//The following functions are the same save for one small difference
//for when you want the item to end up on the ground

View File

@@ -37,7 +37,7 @@ var/global/posibrain_notif_cooldown = 0
/obj/item/device/mmi/posibrain/proc/ping_ghosts(msg, newlymade)
if(newlymade || !posibrain_notif_cooldown)
notify_ghosts("[name] [msg] in [get_area(src)]!", ghost_sound = !newlymade ? 'sound/effects/ghost2.ogg':null, enter_link = "<a href=?src=\ref[src];activate=1>(Click to enter)</a>", source = src, action = NOTIFY_ATTACK)
notify_ghosts("[name] [msg] in [get_area(src)]!", ghost_sound = !newlymade ? 'sound/effects/ghost2.ogg':null, enter_link = "<a href=?src=\ref[src];activate=1>(Click to enter)</a>", source = src, action = NOTIFY_ATTACK, flashwindow = FALSE)
if(!newlymade)
posibrain_notif_cooldown = 1
addtimer(CALLBACK(src, .proc/reset_posibrain_cooldown), askDelay)

View File

@@ -212,6 +212,12 @@
if(lying)
M.visible_message("<span class='notice'>[M] shakes [src] trying to get [p_them()] up!</span>", \
"<span class='notice'>You shake [src] trying to get [p_them()] up!</span>")
else if(check_zone(M.zone_selected) == "head")
M.visible_message("<span class='notice'>[M] gives [src] a pat on the head to make [p_them()] feel better!</span>", \
"<span class='notice'>You give [src] a pat on the head to make [p_them()] feel better!</span>")
if(dna && dna.species && (("tail_lizard" in dna.species.mutant_bodyparts) || (dna.features["tail_human"] != "None") || ("mam_tail" in dna.species.mutant_bodyparts)))
emote("wag") //lewd
else
M.visible_message("<span class='notice'>[M] hugs [src] to make [p_them()] feel better!</span>", \
"<span class='notice'>You hug [src] to make [p_them()] feel better!</span>")
@@ -305,4 +311,3 @@
hit_clothes = head
if(hit_clothes)
hit_clothes.take_damage(damage_amount, damage_type, damage_flag, 0)

View File

@@ -55,6 +55,7 @@
key_third_person = "screeches"
message = "screeches."
mob_type_allowed_typecache = list(/mob/living/carbon/monkey, /mob/living/carbon/alien)
emote_type = EMOTE_AUDIBLE
/datum/emote/living/carbon/sign
key = "sign"

View File

@@ -63,7 +63,7 @@
if(prob(martial_art.deflection_chance))
if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
playsound(src, pick("sound/weapons/bulletflyby.ogg","sound/weapons/bulletflyby2.ogg","sound/weapons/bulletflyby3.ogg"), 75, 1)
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
return 0
if(!(P.original == src && P.firer == src)) //can't block or reflect when shooting yourself

View File

@@ -12,7 +12,7 @@
punchdamagehigh = 30//they are inhumanly strong
punchstunthreshold = 25
attack_verb = "smash"
attack_sound = "sound/weapons/resonator_blast.ogg"
attack_sound = 'sound/weapons/resonator_blast.ogg'
blacklisted = 1
use_skintones = 0
species_traits = list(RADIMMUNE,VIRUSIMMUNE,NOBLOOD,PIERCEIMMUNE,EYECOLOR,NODISMEMBER,NOHUNGER)

View File

@@ -98,7 +98,7 @@
meat = /obj/item/weapon/ore/iron
info_text = "As a <span class='danger'>Plasteel Golem</span>, you are slower, but harder to stun, and hit very hard when punching."
attack_verb = "smash"
attack_sound = "sound/effects/meteorimpact.ogg" //hits pretty hard
attack_sound = 'sound/effects/meteorimpact.ogg' //hits pretty hard
//Immune to ash storms
/datum/species/golem/titanium
@@ -231,7 +231,7 @@
burnmod = 3 //melts easily
brutemod = 0.25
info_text = "As a <span class='danger'>Sand Golem</span>, you are immune to physical bullets and take very little brute damage, but are extremely vulnerable to burn damage. You will also turn to sand when dying, preventing any form of recovery."
attack_sound = "sound/effects/shovel_dig.ogg"
attack_sound = 'sound/effects/shovel_dig.ogg'
/datum/species/golem/sand/spec_death(gibbed, mob/living/carbon/human/H)
H.visible_message("<span class='danger'>[H] turns into a pile of sand!</span>")
@@ -244,7 +244,7 @@
/datum/species/golem/sand/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
if(!(P.original == H && P.firer == H))
if(P.flag == "bullet" || P.flag == "bomb")
playsound(H, "sound/effects/shovel_dig.ogg", 70, 1)
playsound(H, 'sound/effects/shovel_dig.ogg', 70, 1)
H.visible_message("<span class='danger'>The [P.name] sinks harmlessly in [H]'s sandy body!</span>", \
"<span class='userdanger'>The [P.name] sinks harmlessly in [H]'s sandy body!</span>")
return 2
@@ -260,7 +260,7 @@
brutemod = 3 //very fragile
burnmod = 0.25
info_text = "As a <span class='danger'>Glass Golem</span>, you reflect lasers and energy weapons, and are very resistant to burn damage, but you are extremely vulnerable to brute damage. On death, you'll shatter beyond any hope of recovery."
attack_sound = "sound/effects/Glassbr2.ogg"
attack_sound = 'sound/effects/Glassbr2.ogg'
/datum/species/golem/glass/spec_death(gibbed, mob/living/carbon/human/H)
playsound(H, "shatter", 70, 1)
@@ -300,7 +300,7 @@
meat = /obj/item/weapon/ore/bluespace_crystal
info_text = "As a <span class='danger'>Bluespace Golem</span>, are spatially unstable: you will teleport when hit, and you can teleport manually at a long distance."
attack_verb = "bluespace punch"
attack_sound = "sound/effects/phasein.ogg"
attack_sound = 'sound/effects/phasein.ogg'
var/datum/action/innate/unstable_teleport/unstable_teleport
var/teleport_cooldown = 100
@@ -393,7 +393,7 @@
meat = /obj/item/weapon/ore/bananium
info_text = "As a <span class='danger'>Bananium Golem</span>, you are made for pranking. Your body emits natural honks, and you cannot hurt people when punching them. Your skin also emits bananas when damaged."
attack_verb = "honk"
attack_sound = "sound/items/AirHorn2.ogg"
attack_sound = 'sound/items/AirHorn2.ogg'
var/last_honk = 0
var/honkooldown = 0

View File

@@ -10,8 +10,8 @@ var/global/image/plasmaman_on_fire = image("icon"='icons/mob/OnFire.dmi', "icon_
mutantlungs = /obj/item/organ/lungs/plasmaman
dangerous_existence = 1 //So so much
blacklisted = 1 //See above
burnmod = 2
heatmod = 2
burnmod = 1.5
heatmod = 1.5
breathid = "tox"
speedmod = 1
damage_overlay_type = ""//let's not show bloody wounds or burns over bones.

View File

@@ -16,7 +16,6 @@
if(dir & (EAST|WEST)) //Facing east or west
final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass
lying_prev = lying //so we don't try to animate until there's been another change.
if(resize != RESIZE_DEFAULT_SIZE)
changed++
ntransform.Scale(resize)

View File

@@ -462,5 +462,6 @@
user.spin(20, 1)
if(istype(user, /mob/living/silicon/robot))
var/mob/living/silicon/robot/R = user
R.riding_datum.force_dismount()
if(R.riding_datum)
R.riding_datum.force_dismount()
..()

View File

@@ -608,7 +608,7 @@
if(!override)
float(!has_gravity)
/mob/living/proc/float(on)
/mob/living/float(on)
if(throwing)
return
var/fixed = 0

View File

@@ -44,7 +44,6 @@
var/ventcrawler = 0 //0 No vent crawling, 1 vent crawling in the nude, 2 vent crawling always
var/limb_destroyer = 0 //1 Sets AI behavior that allows mobs to target and dismember limbs with their basic attack.
var/floating = 0
var/mob_size = MOB_SIZE_HUMAN
var/metabolism_efficiency = 1 //more or less efficiency to metabolize helpful/harmful reagents and regulate body temperature..
var/list/image/staticOverlays = list()
@@ -75,4 +74,4 @@
var/list/status_effects //a list of all status effects the mob has
var/list/implants = null
var/tesla_ignore = FALSE
var/tesla_ignore = FALSE

View File

@@ -242,7 +242,6 @@ var/list/ai_list = list()
if(statpanel("Status"))
if(!stat)
stat(null, text("System integrity: [(health+100)/2]%"))
stat(null, "Station Time: [worldtime2text()]")
stat(null, text("Connected cyborgs: [connected_robots.len]"))
var/area/borg_area
for(var/mob/living/silicon/robot/R in connected_robots)

View File

@@ -235,4 +235,4 @@
/mob/living/silicon/pai/process()
emitterhealth = Clamp((emitterhealth + emitterregen), -50, emittermaxhealth)
hit_slowdown = Clamp((hit_slowdown - 1), 0, 100)
hit_slowdown = Clamp((hit_slowdown - 1), 0, 100)

View File

@@ -99,3 +99,7 @@
else
SetLuminosity(0)
src << "<span class='notice'>You disable your integrated light.</span>"
/mob/living/silicon/pai/movement_delay()
. = ..()
. += 1 //A bit slower than humans, so they're easier to smash

View File

@@ -302,7 +302,6 @@
else
stat(null, text("No Cell Inserted!"))
stat("Station Time:", worldtime2text())
if(module)
for(var/datum/robot_energy_storage/st in module.storages)
stat("[st.name]:", "[st.energy]/[st.max_energy]")
@@ -598,6 +597,12 @@
update_fire()
#define BORG_CAMERA_BUFFER 30
/mob/living/silicon/robot/proc/do_camera_update(oldLoc)
if(oldLoc != src.loc)
cameranet.updatePortableCamera(src.camera)
updating = 0
/mob/living/silicon/robot/Move(a, b, flag)
var/oldLoc = src.loc
. = ..()
@@ -605,10 +610,7 @@
if(src.camera)
if(!updating)
updating = 1
spawn(BORG_CAMERA_BUFFER)
if(oldLoc != src.loc)
cameranet.updatePortableCamera(src.camera)
updating = 0
addtimer(CALLBACK(.proc/do_camera_update, oldLoc), BORG_CAMERA_BUFFER)
if(module)
if(istype(module, /obj/item/weapon/robot_module/janitor))
var/turf/tile = loc
@@ -1083,4 +1085,4 @@
if(selfdeleting)
if(rider in ridden.buckled_mobs)
ridden.unbuckle_mob(rider)
. = ..()
. = ..()

View File

@@ -21,4 +21,4 @@
/mob/living/silicon/robot/Moved()
. = ..()
if(riding_datum)
riding_datum.on_vehicle_move()
riding_datum.on_vehicle_move()

View File

@@ -410,4 +410,4 @@ Auto Patrol: []"},
..()
/obj/machinery/bot_core/secbot
req_access = list(access_security)
req_access = list(access_security)

View File

@@ -20,7 +20,7 @@
..()
var/area/A = get_area(src)
if(A)
notify_ghosts("A drone shell has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK)
notify_ghosts("A drone shell has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE)
/obj/item/drone_shell/attack_ghost(mob/user)
if(jobban_isbanned(user,"drone"))

View File

@@ -333,6 +333,11 @@
Shoot(A)
spawn(6)
Shoot(A)
/* var/datum/callback/cb = CALLBACK(A, .proc/Shoot)
addtimer(cb, 1)
addtimer(cb, 4)
addtimer(cb, 6)*/
else
Shoot(A)
ranged_cooldown = world.time + ranged_cooldown_time

View File

@@ -115,6 +115,12 @@ Difficulty: Hard
bloodspell.phased = 1
internal = new/obj/item/device/gps/internal/bubblegum(src)
/mob/living/simple_animal/hostile/megafauna/bubblegum/grant_achievement(medaltype,scoretype)
..()
SSshuttle.shuttle_purchase_requirements_met |= "bubblegum"
/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon)
if(!charging)
..()
@@ -153,7 +159,7 @@ Difficulty: Hard
var/obj/effect/overlay/temp/decoy/D = new /obj/effect/overlay/temp/decoy(loc,src)
animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 3)
sleep(3)
throw_at(T, get_dist(src, T), 0.5, src, 0, callback = CALLBACK(src, .charge_end, bonus_charges))
throw_at(T, get_dist(src, T), 1, src, 0, callback = CALLBACK(src, .charge_end, bonus_charges))
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge_end(bonus_charges)
charging = 0

View File

@@ -550,4 +550,4 @@
/mob/living/simple_animal/buckle_mob(mob/living/buckled_mob, force = 0, check_loc = 1)
. = ..()
riding_datum = new/datum/riding/animal
riding_datum = new/datum/riding/animal

View File

@@ -550,7 +550,9 @@ var/next_mob_id = 0
stat(null, "Map: [MAP_NAME]")
if(nextmap && istype(nextmap))
stat(null, "Next Map: [nextmap.friendlyname]")
stat(null, "Server Time: [time2text(world.realtime, "YYYY-MM-DD hh:mm")]")
stat(null, "Server Time: [time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss")]")
stat(null, "Station Time: [worldtime2text()]")
stat(null, "Time Dilation: [round(SStime_track.time_dilation_current,1)]% AVG:([round(SStime_track.time_dilation_avg_fast,1)]%, [round(SStime_track.time_dilation_avg,1)]%, [round(SStime_track.time_dilation_avg_slow,1)]%)")
if(SSshuttle.emergency)
var/ETA = SSshuttle.emergency.getModeStr()
if(ETA)
@@ -676,6 +678,9 @@ var/next_mob_id = 0
var/mob/living/L = src
if(L.has_status_effect(/datum/status_effect/freon))
canmove = 0
if(!lying && lying_prev)
if(client)
client.move_delay = world.time + movement_delay()
lying_prev = lying
return canmove
@@ -739,10 +744,10 @@ var/next_mob_id = 0
if(mind)
return mind.grab_ghost(force = force)
/mob/proc/notify_ghost_cloning(var/message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", var/sound = 'sound/effects/genetics.ogg', var/atom/source = null)
/mob/proc/notify_ghost_cloning(var/message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", var/sound = 'sound/effects/genetics.ogg', var/atom/source = null, flashwindow)
var/mob/dead/observer/ghost = get_ghost()
if(ghost)
ghost.notify_cloning(message, sound, source)
ghost.notify_cloning(message, sound, source, flashwindow)
return ghost
/mob/proc/AddSpell(obj/effect/proc_holder/spell/S)

View File

@@ -378,12 +378,14 @@ var/static/regex/firstname = new("^\[^\\s-\]+") //First word before whitespace o
/mob/proc/reagent_check(datum/reagent/R) // utilized in the species code
return 1
/proc/notify_ghosts(var/message, var/ghost_sound = null, var/enter_link = null, var/atom/source = null, var/image/alert_overlay = null, var/action = NOTIFY_JUMP) //Easy notification of ghosts.
/proc/notify_ghosts(var/message, var/ghost_sound = null, var/enter_link = null, var/atom/source = null, var/image/alert_overlay = null, var/action = NOTIFY_JUMP, flashwindow = TRUE) //Easy notification of ghosts.
for(var/mob/dead/observer/O in player_list)
if(O.client)
O << "<span class='ghostalert'>[message][(enter_link) ? " [enter_link]" : ""]<span>"
if(ghost_sound)
O << sound(ghost_sound)
if(flashwindow)
window_flash(O.client)
if(source)
var/obj/screen/alert/notify_action/A = O.throw_alert("\ref[source]_notify_action", /obj/screen/alert/notify_action)
if(A)

View File

@@ -56,6 +56,5 @@
M.key = key
if(delete_old_mob)
spawn(1)
qdel(src)
QDEL_IN(src, 1)
return M

View File

@@ -27,7 +27,4 @@
loc = pick(watch_locations)
*/
new_player_panel()
spawn(40)
if(client)
client.playtitlemusic()
client.playtitlemusic()

View File

@@ -24,6 +24,7 @@
user << "<span class='notice'>You install \the [H] into \the [src].</span>"
H.holder = src
H.forceMove(src)
H.on_install(src, user)

View File

@@ -68,14 +68,18 @@
var/ejected = 0
if(stored_card && (!slot || slot == 1))
stored_card.forceMove(get_turf(src))
stored_card.verb_pickup()
if(user)
user.put_in_hands(stored_card)
else
stored_card.forceMove(get_turf(src))
stored_card = null
ejected++
if(stored_card2 && (!slot || slot == 2))
stored_card2.forceMove(get_turf(src))
stored_card2.verb_pickup()
if(user)
user.put_in_hands(stored_card2)
else
stored_card2.forceMove(get_turf(src))
stored_card2 = null
ejected++

View File

@@ -100,11 +100,7 @@
else if(istype(over_object, /obj/screen/inventory/hand))
var/obj/screen/inventory/hand/H = over_object
if(!remove_item_from_storage(M))
M.temporarilyRemoveItemFromInventory(src, TRUE)
if(!M.put_in_hand(src, H.held_index))
qdel(src) //rip
return
M.putItemFromInventoryInHandIfPossible(src, H.held_index)
add_fingerprint(M)

View File

@@ -56,11 +56,7 @@
else if(istype(over_object, /obj/screen/inventory/hand))
var/obj/screen/inventory/hand/H = over_object
if(!remove_item_from_storage(M))
M.temporarilyRemoveItemFromInventory(src, TRUE)
if(!M.put_in_hand(src, H.held_index))
qdel(src)
return
M.putItemFromInventoryInHandIfPossible(src, H.held_index)
add_fingerprint(M)

View File

@@ -147,16 +147,16 @@
break
else if(toner >= 5 && !busy && check_ass()) //You have to be sitting on the copier and either be a xeno or a human without clothes on.
if(isalienadult(ass) || istype(ass,/mob/living/simple_animal/hostile/alien)) //Xenos have their own asses, thanks to Pybro.
temp_img = icon("icons/ass/assalien.png")
temp_img = icon('icons/ass/assalien.png')
else if(ishuman(ass)) //Suit checks are in check_ass
if(ass.gender == MALE)
temp_img = icon("icons/ass/assmale.png")
temp_img = icon('icons/ass/assmale.png')
else if(ass.gender == FEMALE)
temp_img = icon("icons/ass/assfemale.png")
temp_img = icon('icons/ass/assfemale.png')
else //In case anyone ever makes the generic ass. For now I'll be using male asses.
temp_img = icon("icons/ass/assmale.png")
temp_img = icon('icons/ass/assmale.png')
else if(isdrone(ass)) //Drones are hot
temp_img = icon("icons/ass/assdrone.png")
temp_img = icon('icons/ass/assdrone.png')
else
break
var/obj/item/weapon/photo/p = new /obj/item/weapon/photo (loc)

View File

@@ -69,7 +69,6 @@ var/const/GRAV_NEEDS_WRENCH = 3
/obj/machinery/gravity_generator/part/Destroy()
if(main_part)
qdel(main_part)
return QDEL_HINT_LETMELIVE
set_broken()
return ..()
@@ -137,7 +136,8 @@ var/const/GRAV_NEEDS_WRENCH = 3
update_list()
for(var/obj/machinery/gravity_generator/part/O in parts)
O.main_part = null
qdel(O)
if(!QDESTROYING(O))
qdel(O)
return ..()
/obj/machinery/gravity_generator/main/proc/setup_parts()

View File

@@ -91,7 +91,7 @@
if(ticker && ticker.current_state == GAME_STATE_PLAYING)
message_admins("Emitter deleted at ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
log_game("Emitter deleted at ([x],[y],[z])")
investigate_log("<font color='red'>deleted</font> at ([x],[y],[z])","singulo")
investigate_log("<font color='red'>deleted</font> at ([x],[y],[z]) at [get_area(src)]","singulo")
return ..()
/obj/machinery/power/emitter/update_icon()
@@ -113,13 +113,13 @@
user << "<span class='notice'>You turn off \the [src].</span>"
message_admins("Emitter turned off by [key_name_admin(user)](<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[user]'>FLW</A>) in ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
log_game("Emitter turned off by [key_name(user)] in ([x],[y],[z])")
investigate_log("turned <font color='red'>off</font> by [key_name(user)]","singulo")
investigate_log("turned <font color='red'>off</font> by [key_name(user)] at [get_area(src)]","singulo")
else
src.active = 1
user << "<span class='notice'>You turn on \the [src].</span>"
src.shot_number = 0
src.fire_delay = maximum_fire_delay
investigate_log("turned <font color='green'>on</font> by [key_name(user)]","singulo")
investigate_log("turned <font color='green'>on</font> by [key_name(user)] at [get_area(src)]","singulo")
update_icon()
else
user << "<span class='warning'>The controls are locked!</span>"
@@ -160,12 +160,12 @@
if(!powered)
powered = 1
update_icon()
investigate_log("regained power and turned <font color='green'>on</font>","singulo")
investigate_log("regained power and turned <font color='green'>on</font> at [get_area(src)]","singulo")
else
if(powered)
powered = 0
update_icon()
investigate_log("lost power and turned <font color='red'>off</font>","singulo")
investigate_log("lost power and turned <font color='red'>off</font> at [get_area(src)]","singulo")
log_game("Emitter lost power in ([x],[y],[z])")
return
if(!check_delay())

View File

@@ -152,4 +152,4 @@
if(anchored && !panel_open)
flick("grounding_rodhit", src)
else
..()
..()

View File

@@ -116,7 +116,7 @@
projectile_type = /obj/item/projectile/beam/disabler
select_name = "disable"
e_cost = 50
fire_sound = "sound/weapons/taser2.ogg"
fire_sound = 'sound/weapons/taser2.ogg'
/obj/item/ammo_casing/energy/plasma
projectile_type = /obj/item/projectile/plasma
@@ -133,7 +133,7 @@
/obj/item/ammo_casing/energy/wormhole
projectile_type = /obj/item/projectile/beam/wormhole
e_cost = 0
fire_sound = "sound/weapons/pulse3.ogg"
fire_sound = 'sound/weapons/pulse3.ogg'
var/obj/item/weapon/gun/energy/wormhole_projector/gun = null
select_name = "blue"
@@ -184,7 +184,7 @@
/obj/item/ammo_casing/energy/gravityrepulse
projectile_type = /obj/item/projectile/gravityrepulse
e_cost = 0
fire_sound = "sound/weapons/wave.ogg"
fire_sound = 'sound/weapons/wave.ogg'
select_name = "repulse"
delay = 50
var/obj/item/weapon/gun/energy/gravity_gun/gun = null
@@ -195,7 +195,7 @@
/obj/item/ammo_casing/energy/gravityattract
projectile_type = /obj/item/projectile/gravityattract
e_cost = 0
fire_sound = "sound/weapons/wave.ogg"
fire_sound = 'sound/weapons/wave.ogg'
select_name = "attract"
delay = 50
var/obj/item/weapon/gun/energy/gravity_gun/gun = null
@@ -207,7 +207,7 @@
/obj/item/ammo_casing/energy/gravitychaos
projectile_type = /obj/item/projectile/gravitychaos
e_cost = 0
fire_sound = "sound/weapons/wave.ogg"
fire_sound = 'sound/weapons/wave.ogg'
select_name = "chaos"
delay = 50
var/obj/item/weapon/gun/energy/gravity_gun/gun = null

View File

@@ -63,14 +63,11 @@
if(!over_object)
return
if(!M.restrained() && !M.stat)
if(!M.incapacitated())
if(istype(over_object, /obj/screen/inventory/hand))
var/obj/screen/inventory/hand/H = over_object
if(!M.temporarilyRemoveItemFromInventory(src))
return
if(!M.put_in_hand(src, H.held_index))
qdel(src)
M.putItemFromInventoryInHandIfPossible(src, H.held_index)
/obj/item/weapon/minigunpack/update_icon()

View File

@@ -4,7 +4,7 @@
/obj/item/weapon/gun/magic/staff/change
name = "staff of change"
desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself"
fire_sound = "sound/magic/Staff_Change.ogg"
fire_sound = 'sound/magic/Staff_Change.ogg'
ammo_type = /obj/item/ammo_casing/magic/change
icon_state = "staffofchange"
item_state = "staffofchange"
@@ -12,7 +12,7 @@
/obj/item/weapon/gun/magic/staff/animate
name = "staff of animation"
desc = "An artefact that spits bolts of life-force which causes objects which are hit by it to animate and come to life! This magic doesn't affect machines."
fire_sound = "sound/magic/Staff_animation.ogg"
fire_sound = 'sound/magic/Staff_animation.ogg'
ammo_type = /obj/item/ammo_casing/magic/animate
icon_state = "staffofanimation"
item_state = "staffofanimation"
@@ -20,7 +20,7 @@
/obj/item/weapon/gun/magic/staff/healing
name = "staff of healing"
desc = "An artefact that spits bolts of restoring magic which can remove ailments of all kinds and even raise the dead."
fire_sound = "sound/magic/Staff_Healing.ogg"
fire_sound = 'sound/magic/Staff_Healing.ogg'
ammo_type = /obj/item/ammo_casing/magic/heal
icon_state = "staffofhealing"
item_state = "staffofhealing"
@@ -31,7 +31,7 @@
/obj/item/weapon/gun/magic/staff/chaos
name = "staff of chaos"
desc = "An artefact that spits bolts of chaotic magic that can potentially do anything."
fire_sound = "sound/magic/Staff_Chaos.ogg"
fire_sound = 'sound/magic/Staff_Chaos.ogg'
ammo_type = /obj/item/ammo_casing/magic/chaos
icon_state = "staffofchaos"
item_state = "staffofchaos"
@@ -49,7 +49,7 @@
/obj/item/weapon/gun/magic/staff/door
name = "staff of door creation"
desc = "An artefact that spits bolts of transformative magic that can create doors in walls."
fire_sound = "sound/magic/Staff_Door.ogg"
fire_sound = 'sound/magic/Staff_Door.ogg'
ammo_type = /obj/item/ammo_casing/magic/door
icon_state = "staffofdoor"
item_state = "staffofdoor"
@@ -60,7 +60,7 @@
/obj/item/weapon/gun/magic/staff/honk
name = "staff of the honkmother"
desc = "Honk"
fire_sound = "sound/items/airhorn.ogg"
fire_sound = 'sound/items/airhorn.ogg'
ammo_type = /obj/item/ammo_casing/magic/honk
icon_state = "honker"
item_state = "honker"
@@ -70,7 +70,7 @@
/obj/item/weapon/gun/magic/staff/spellblade
name = "spellblade"
desc = "A deadly combination of laziness and boodlust, this blade allows the user to dismember their enemies without all the hard work of actually swinging the sword."
fire_sound = "sound/magic/Fireball.ogg"
fire_sound = 'sound/magic/Fireball.ogg'
ammo_type = /obj/item/ammo_casing/magic/spellblade
icon_state = "spellblade"
item_state = "spellblade"

View File

@@ -60,7 +60,7 @@
/obj/item/weapon/gun/magic/wand/death
name = "wand of death"
desc = "This deadly wand overwhelms the victim's body with pure energy, slaying them without fail."
fire_sound = "sound/magic/WandoDeath.ogg"
fire_sound = 'sound/magic/WandoDeath.ogg'
ammo_type = /obj/item/ammo_casing/magic/death
icon_state = "deathwand"
max_charges = 3 //3, 2, 2, 1
@@ -82,7 +82,7 @@
name = "wand of healing"
desc = "This wand uses healing magics to heal and revive. They are rarely utilized within the Wizard Federation for some reason."
ammo_type = /obj/item/ammo_casing/magic/heal
fire_sound = "sound/magic/Staff_Healing.ogg"
fire_sound = 'sound/magic/Staff_Healing.ogg'
icon_state = "revivewand"
max_charges = 10 //10, 5, 5, 4
@@ -105,7 +105,7 @@
desc = "This wand is attuned to chaos and will radically alter the victim's form."
ammo_type = /obj/item/ammo_casing/magic/change
icon_state = "polywand"
fire_sound = "sound/magic/Staff_Change.ogg"
fire_sound = 'sound/magic/Staff_Change.ogg'
max_charges = 10 //10, 5, 5, 4
/obj/item/weapon/gun/magic/wand/polymorph/zap_self(mob/living/user)
@@ -121,7 +121,7 @@
name = "wand of teleportation"
desc = "This wand will wrench targets through space and time to move them somewhere else."
ammo_type = /obj/item/ammo_casing/magic/teleport
fire_sound = "sound/magic/Wand_Teleport.ogg"
fire_sound = 'sound/magic/Wand_Teleport.ogg'
icon_state = "telewand"
max_charges = 10 //10, 5, 5, 4
no_den_usage = 1
@@ -143,7 +143,7 @@
desc = "This particular wand can create doors in any wall for the unscrupulous wizard who shuns teleportation magics."
ammo_type = /obj/item/ammo_casing/magic/door
icon_state = "doorwand"
fire_sound = "sound/magic/Staff_Door.ogg"
fire_sound = 'sound/magic/Staff_Door.ogg'
max_charges = 20 //20, 10, 10, 7
no_den_usage = 1
@@ -159,7 +159,7 @@
/obj/item/weapon/gun/magic/wand/fireball
name = "wand of fireball"
desc = "This wand shoots scorching balls of fire that explode into destructive flames."
fire_sound = "sound/magic/Fireball.ogg"
fire_sound = 'sound/magic/Fireball.ogg'
ammo_type = /obj/item/ammo_casing/magic/fireball
icon_state = "firewand"
max_charges = 8 //8, 4, 4, 3

View File

@@ -239,7 +239,7 @@
name = "repulsion bolt"
icon = 'icons/effects/effects.dmi'
icon_state = "chronofield"
hitsound = "sound/weapons/wave.ogg"
hitsound = 'sound/weapons/wave.ogg'
damage = 0
damage_type = BRUTE
nodamage = 1
@@ -267,7 +267,7 @@
name = "attraction bolt"
icon = 'icons/effects/effects.dmi'
icon_state = "chronofield"
hitsound = "sound/weapons/wave.ogg"
hitsound = 'sound/weapons/wave.ogg'
damage = 0
damage_type = BRUTE
nodamage = 1
@@ -294,7 +294,7 @@
name = "gravitational blast"
icon = 'icons/effects/effects.dmi'
icon_state = "chronofield"
hitsound = "sound/weapons/wave.ogg"
hitsound = 'sound/weapons/wave.ogg'
damage = 0
damage_type = BRUTE
nodamage = 1

View File

@@ -15,6 +15,7 @@
var/screen = "home"
var/analyzeVars[0]
var/useramount = 30 // Last used amount
layer = 2.9
/obj/machinery/chem_master/New()
create_reagents(100)

View File

@@ -107,6 +107,10 @@
return
else
if(isturf(target) && reagents.reagent_list.len && thrownby)
add_logs(thrownby, target, "splashed (thrown) [english_list(reagents.reagent_list)]", "at [target][COORD(target)]")
log_game("[key_name(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] at [COORD(target)].")
message_admins("[key_name_admin(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] at [ADMIN_COORDJMP(target)].")
visible_message("<span class='notice'>[src] spills its contents all over [target].</span>")
reagents.reaction(target, TOUCH)
if(QDELETED(src))
@@ -118,4 +122,4 @@
if(is_open_container())
reagents.chem_temp = max(reagents.chem_temp, 1000)
reagents.handle_reactions()
..()
..()

View File

@@ -28,6 +28,10 @@
for(var/datum/reagent/A in reagents.reagent_list)
R += A.id + " ("
R += num2text(A.volume) + "),"
if(isturf(target) && reagents.reagent_list.len && thrownby)
add_logs(thrownby, target, "splashed [english_list(reagents.reagent_list)]", "at [target][COORD(target)]")
log_game("[key_name(thrownby)] splashed [english_list(reagents.reagent_list)] at [COORD(target)].")
message_admins("[key_name_admin(thrownby)] splashed [english_list(reagents.reagent_list)] at [ADMIN_COORDJMP(target)].")
reagents.reaction(M, TOUCH)
add_logs(user, M, "splashed", R)
reagents.clear_reagents()

View File

@@ -103,7 +103,7 @@
name = "antitoxin pill"
desc = "Neutralizes many common toxins."
icon_state = "pill17"
list_reagents = list("charcoal" = 50)
list_reagents = list("charcoal" = 10)
roundstart = 1
/obj/item/weapon/reagent_containers/pill/epinephrine
name = "epinephrine pill"

View File

@@ -264,8 +264,7 @@
found++
if(found > 1)
qdel(P, force=TRUE)
world.log << "Map warning: Shuttle Template [S.mappath] \
has multiple mobile docking ports."
log_world("Map warning: Shuttle Template [S.mappath] has multiple mobile docking ports.")
else if(!M.timid)
// The shuttle template we loaded isn't "timid" which means
// it's already registered with the shuttles subsystem.
@@ -277,11 +276,9 @@
else
preview_shuttle = P
if(istype(P, /obj/docking_port/stationary))
world.log << "Map warning: Shuttle Template [S.mappath] has a \
stationary docking port."
log_world("Map warning: Shuttle Template [S.mappath] has a stationary docking port.")
if(!found)
var/msg = "load_template(): Shuttle Template [S.mappath] has no \
mobile docking port. Aborting import."
var/msg = "load_template(): Shuttle Template [S.mappath] has no mobile docking port. Aborting import."
for(var/T in affected)
var/turf/T0 = T
T0.empty()

View File

@@ -255,3 +255,19 @@
mover << "You don't have enough money to enter the main shuttle. You'll have to fly coach."
return 0
/mob/living/simple_animal/hostile/bear/fightpit
name = "fight pit bear"
desc = "This bear's trained through ancient Russian secrets to fear the walls of its glass prison."
environment_smash = 0
/obj/effect/decal/hammerandsickle
name = "hammer and sickle"
desc = "Communism powerful force."
icon = 'icons/effects/96x96.dmi'
icon_state = "communist"
layer = ABOVE_OPEN_TURF_LAYER
pixel_x = -32
pixel_y = -32
/obj/effect/decal/hammerandsickle/shuttleRotate(rotation)
setDir(angle2dir(rotation+dir2angle(dir))) // No parentcall, rest of the rotate code breaks the pixel offset.

View File

@@ -110,7 +110,7 @@
projectile_type = /obj/item/projectile/magic/aoe/fireball
base_icon_state = "fireball"
action_icon_state = "fireball0"
sound = "sound/magic/Fireball.ogg"
sound = 'sound/magic/Fireball.ogg'
active_msg = "You prepare to cast your fireball spell!"
deactive_msg = "You extinguish your fireball... for now."
active = FALSE

View File

@@ -5,8 +5,8 @@
var/randomise_selection = 0 //if it lets the usr choose the teleport loc or picks it from the list
var/invocation_area = 1 //if the invocation appends the selected area
var/sound1 = "sound/weapons/ZapBang.ogg"
var/sound2 = "sound/weapons/ZapBang.ogg"
var/sound1 = 'sound/weapons/ZapBang.ogg'
var/sound2 = 'sound/weapons/ZapBang.ogg'
/obj/effect/proc_holder/spell/targeted/area_teleport/perform(list/targets, recharge = 1,mob/living/user = usr)
var/thearea = before_cast(targets)

View File

@@ -32,7 +32,7 @@
return
var/list/masks = list(/obj/item/clothing/mask/spig, /obj/item/clothing/mask/cowmask, /obj/item/clothing/mask/horsehead)
var/list/mSounds = list("sound/magic/PigHead_curse.ogg", "sound/magic/CowHead_Curse.ogg", "sound/magic/HorseHead_curse.ogg")
var/list/mSounds = list('sound/magic/PigHead_curse.ogg', 'sound/magic/CowHead_Curse.ogg', 'sound/magic/HorseHead_curse.ogg')
var/randM = rand(1,3)

View File

@@ -95,5 +95,5 @@
else if(burnt_out)
L << "<span class='caution'>[charged_item] doesn't seem to be reacting to the spell...</span>"
else
playsound(get_turf(L), "sound/magic/Charge.ogg", 50, 1)
playsound(get_turf(L), 'sound/magic/Charge.ogg', 50, 1)
L << "<span class='notice'>[charged_item] suddenly feels very warm!</span>"

View File

@@ -6,7 +6,7 @@
var/emp_light = 3
action_icon_state = "emp"
sound = "sound/weapons/ZapBang.ogg"
sound = 'sound/weapons/ZapBang.ogg'
/obj/effect/proc_holder/spell/targeted/emplosion/cast(list/targets,mob/user = usr)
playsound(get_turf(user), sound, 50,1)

View File

@@ -6,7 +6,7 @@
clothes_req = 0
invocation = "TARCOL MINTI ZHERI"
invocation_type = "shout"
sound = "sound/magic/ForceWall.ogg"
sound = 'sound/magic/ForceWall.ogg'
action_icon_state = "shield"
range = -1
include_user = 1

View File

@@ -42,7 +42,7 @@
name = "\improper disintegrating touch"
desc = "This hand of mine glows with an awesome power!"
catchphrase = "EI NATH!!"
on_use_sound = "sound/magic/Disintegrate.ogg"
on_use_sound = 'sound/magic/Disintegrate.ogg'
icon_state = "disintegrate"
item_state = "disintegrate"
@@ -60,7 +60,7 @@
name = "\improper petrifying touch"
desc = "That's the bottom line, because flesh to stone said so!"
catchphrase = "STAUN EI!!"
on_use_sound = "sound/magic/FleshToStone.ogg"
on_use_sound = 'sound/magic/FleshToStone.ogg'
icon_state = "fleshtostone"
item_state = "fleshtostone"

View File

@@ -13,7 +13,7 @@
action_icon_state = "knock"
/obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets,mob/user = usr)
user << sound("sound/magic/Knock.ogg")
user << sound('sound/magic/Knock.ogg')
for(var/turf/T in targets)
for(var/obj/machinery/door/door in T.contents)
INVOKE_ASYNC(src, .proc/open_door, door)

View File

@@ -7,7 +7,7 @@
var/list/effects
var/ready = TRUE
centcom_cancast = FALSE
sound = "sound/effects/magic.ogg"
sound = 'sound/effects/magic.ogg'
cooldown_min = 300
level_max = 0

View File

@@ -103,10 +103,10 @@
if(!L.put_in_hands(item_to_retrieve))
item_to_retrieve.loc = L.loc
item_to_retrieve.loc.visible_message("<span class='caution'>The [item_to_retrieve.name] suddenly appears!</span>")
playsound(get_turf(L),"sound/magic/SummonItems_generic.ogg",50,1)
playsound(get_turf(L), 'sound/magic/SummonItems_generic.ogg', 50, 1)
else
item_to_retrieve.loc.visible_message("<span class='caution'>The [item_to_retrieve.name] suddenly appears in [L]'s hand!</span>")
playsound(get_turf(L),"sound/magic/SummonItems_generic.ogg",50,1)
playsound(get_turf(L), 'sound/magic/SummonItems_generic.ogg', 50, 1)
if(message)

View File

@@ -58,4 +58,4 @@
cooldown_min = 200 //100 deciseconds reduction per rank
action_icon_state = "statue"
sound = "sound/magic/FleshToStone.ogg"
sound = 'sound/magic/FleshToStone.ogg'

View File

@@ -8,8 +8,8 @@
var/include_space = 0 //whether it includes space tiles in possible teleport locations
var/include_dense = 0 //whether it includes dense tiles in possible teleport locations
var/sound1 = "sound/weapons/ZapBang.ogg"
var/sound2 = "sound/weapons/ZapBang.ogg"
var/sound1 = 'sound/weapons/ZapBang.ogg'
var/sound2 = 'sound/weapons/ZapBang.ogg'
/obj/effect/proc_holder/spell/targeted/turf_teleport/cast(list/targets,mob/user = usr)
playsound(get_turf(user), sound1, 50,1)

View File

@@ -25,11 +25,11 @@
proj_trail_icon_state = "magicmd"
action_icon_state = "magicm"
sound = "sound/magic/MAGIC_MISSILE.ogg"
sound = 'sound/magic/MAGIC_MISSILE.ogg'
/obj/effect/proc_holder/spell/targeted/inflict_handler/magic_missile
amt_weakened = 3
sound = "sound/magic/MM_Hit.ogg"
sound = 'sound/magic/MM_Hit.ogg'
/obj/effect/proc_holder/spell/targeted/genetic/mutate
name = "Mutate"
@@ -48,7 +48,7 @@
cooldown_min = 300 //25 deciseconds reduction per rank
action_icon_state = "mutate"
sound = "sound/magic/Mutate.ogg"
sound = 'sound/magic/Mutate.ogg'
/obj/effect/proc_holder/spell/targeted/smoke
@@ -82,7 +82,7 @@
emp_heavy = 6
emp_light = 10
sound = "sound/magic/Disable_Tech.ogg"
sound = 'sound/magic/Disable_Tech.ogg'
/obj/effect/proc_holder/spell/targeted/turf_teleport/blink
name = "Blink"
@@ -105,8 +105,8 @@
outer_tele_radius = 6
action_icon_state = "blink"
sound1="sound/magic/blink.ogg"
sound2="sound/magic/blink.ogg"
sound1 = 'sound/magic/blink.ogg'
sound2 = 'sound/magic/blink.ogg'
/obj/effect/proc_holder/spell/targeted/turf_teleport/blink/cult
name = "quickstep"
@@ -130,8 +130,8 @@
smoke_spread = 1
smoke_amt = 2
sound1="sound/magic/Teleport_diss.ogg"
sound2="sound/magic/Teleport_app.ogg"
sound1 = 'sound/magic/Teleport_diss.ogg'
sound2 = 'sound/magic/Teleport_app.ogg'
/obj/effect/proc_holder/spell/aoe_turf/conjure/timestop
name = "Stop Time"
@@ -159,7 +159,7 @@
range = 1
summon_type = list(/mob/living/simple_animal/hostile/carp)
cast_sound = "sound/magic/Summon_Karp.ogg"
cast_sound = 'sound/magic/Summon_Karp.ogg'
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct
@@ -176,7 +176,7 @@
summon_type = list(/obj/structure/constructshell)
action_icon_state = "artificer"
cast_sound = "sound/magic/SummonItems_generic.ogg"
cast_sound = 'sound/magic/SummonItems_generic.ogg'
/obj/effect/proc_holder/spell/aoe_turf/conjure/creature
@@ -192,7 +192,7 @@
range = 3
summon_type = list(/mob/living/simple_animal/hostile/creature)
cast_sound = "sound/magic/SummonItems_generic.ogg"
cast_sound = 'sound/magic/SummonItems_generic.ogg'
/obj/effect/proc_holder/spell/targeted/trigger/blind
name = "Blind"
@@ -221,12 +221,12 @@
/obj/effect/proc_holder/spell/targeted/inflict_handler/blind
amt_eye_blind = 10
amt_eye_blurry = 20
sound="sound/magic/Blind.ogg"
sound = 'sound/magic/Blind.ogg'
/obj/effect/proc_holder/spell/targeted/genetic/blind
mutations = list(BLINDMUT)
duration = 300
sound="sound/magic/Blind.ogg"
sound = 'sound/magic/Blind.ogg'
/obj/effect/proc_holder/spell/aoe_turf/repulse
name = "Repulse"
desc = "This spell throws everything around the user away."
@@ -305,7 +305,7 @@
include_user = 1
selection_type = "view"
action_icon_state = "sacredflame"
sound = "sound/magic/Fireball.ogg"
sound = 'sound/magic/Fireball.ogg'
/obj/effect/proc_holder/spell/targeted/sacred_flame/cast(list/targets, mob/user = usr)
for(var/mob/living/L in targets)

View File

@@ -793,6 +793,7 @@
see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
night_vision = TRUE
owner.update_sight()
/obj/item/organ/eyes/night_vision/alien
name = "alien eyes"

View File

@@ -507,7 +507,7 @@ var/static/regex/multispin_words = regex("like a record baby|right round")
//HONK
else if((findtext(message, honk_words)))
next_command = world.time + cooldown_meme
addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, get_turf(owner), "sound/items/bikehorn.ogg", 300, 1), 25)
addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, get_turf(owner), 'sound/items/bikehorn.ogg', 300, 1), 25)
if(owner.mind && owner.mind.assigned_role == "Clown")
for(var/mob/living/carbon/C in listeners)
C.slip(0,7 * power_multiplier)