Merge remote-tracking branch 'origin/master'

This commit is contained in:
Flint
2020-01-19 19:46:35 -06:00
359 changed files with 4948 additions and 3166 deletions
+1 -1
View File
@@ -130,7 +130,7 @@
if (smooth & SMOOTH_DIAGONAL)
for (var/O in overlays)
var/image/I = O
if (copytext(I.icon_state, 1, 3) == "d-")
if(copytext(I.icon_state, 1, 3) == "d-") //3 == length("d-") + 1
return
var/stuff_on_wall = 0
+2
View File
@@ -178,6 +178,8 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
desc = "A device used to rapidly pipe things."
icon = 'icons/obj/tools.dmi'
icon_state = "rpd"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
flags_1 = CONDUCT_1
force = 10
throwforce = 10
+4 -1
View File
@@ -7,7 +7,7 @@ RSF
name = "\improper Rapid-Service-Fabricator"
desc = "A device used to rapidly deploy service items."
icon = 'icons/obj/tools.dmi'
icon_state = "rcd"
icon_state = "rsf"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
opacity = 0
@@ -35,6 +35,7 @@ RSF
matter += 10
playsound(src.loc, 'sound/machines/click.ogg', 10, TRUE)
to_chat(user, "<span class='notice'>The RSF now holds [matter]/30 fabrication-units.</span>")
icon_state = "rsf"
else
return ..()
@@ -69,9 +70,11 @@ RSF
var/mob/living/silicon/robot/R = user
if(!R.cell || R.cell.charge < 200)
to_chat(user, "<span class='warning'>You do not have enough power to use [src].</span>")
icon_state = "rsf_empty"
return
else if (matter < 1)
to_chat(user, "<span class='warning'>\The [src] doesn't have enough matter left.</span>")
icon_state = "rsf_empty"
return
var/turf/T = get_turf(A)
+10 -22
View File
@@ -398,30 +398,18 @@ update_label()
if(user.incapacitated())
return
if(popup_input == "Forge/Reset" && !forged)
var/input_text = input(user, "What name would you like to put on this card? Leave blank to randomise.", "Agent card name", registered_name ? registered_name : (ishuman(user) ? user.real_name : user.name))as text | null
if (isnull(input_text))
return
var/target_name = copytext(sanitize(input_text), 1, 26)
if(!target_name || target_name == "Unknown" || target_name == "floor" || target_name == "wall" || target_name == "r-wall") //Same as mob/dead/new_player/preferences.dm
if (ishuman(user))
var/mob/living/carbon/human/human_agent = user
// Invalid/blank names give a randomly generated one.
if (human_agent.gender == "male")
registered_name = "[pick(GLOB.first_names_male)] [pick(GLOB.last_names)]"
else if (human_agent.gender == "female")
registered_name = "[pick(GLOB.first_names_female)] [pick(GLOB.last_names)]"
else
registered_name = "[pick(GLOB.first_names)] [pick(GLOB.last_names)]"
var/input_name = stripped_input(user, "What name would you like to put on this card? Leave blank to randomise.", "Agent card name", registered_name ? registered_name : (ishuman(user) ? user.real_name : user.name), MAX_NAME_LEN)
input_name = reject_bad_name(input_name)
if(!input_name)
// Invalid/blank names give a randomly generated one.
if(user.gender == MALE)
input_name = "[pick(GLOB.first_names_male)] [pick(GLOB.last_names)]"
else if(user.gender == FEMALE)
input_name = "[pick(GLOB.first_names_female)] [pick(GLOB.last_names)]"
else
alert ("Invalid name.")
return
else
registered_name = target_name
input_name = "[pick(GLOB.first_names)] [pick(GLOB.last_names)]"
var/target_occupation = copytext(sanitize(input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", assignment ? assignment : "Assistant") as text | null),1,MAX_MESSAGE_LEN)
var/target_occupation = stripped_input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", assignment ? assignment : "Assistant", MAX_MESSAGE_LEN)
if(!target_occupation)
registered_name = ""
return
+1 -1
View File
@@ -217,7 +217,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/clothing/mask/cigarette/extinguish()
if(!lit)
return
name = copytext(name,5,length(name)+1)
name = copytext_char(name, 5) //5 == length_char("lit ") + 1
attack_verb = null
hitsound = null
damtype = BRUTE
+1 -1
View File
@@ -390,7 +390,7 @@
to_chat(user, "<span class='notice'>You spray a [temp] on \the [target.name]</span>")
if(length(text_buffer) > 1)
text_buffer = copytext(text_buffer,2)
text_buffer = copytext(text_buffer, length(text_buffer[1]) + 1)
SStgui.update_uis(src)
if(post_noise)
+10 -22
View File
@@ -306,7 +306,6 @@
var/req_defib = TRUE
var/combat = FALSE //If it penetrates armor and gives additional functionality
var/grab_ghost = FALSE
var/tlimit = DEFIB_TIME_LIMIT * 10
var/base_icon_state = "defibpaddles"
/obj/item/twohanded/shockpaddles/ComponentInitialize()
@@ -356,13 +355,16 @@
cooldown = FALSE
update_icon()
/obj/item/twohanded/shockpaddles/New(mainunit)
..()
if(check_defib_exists(mainunit, src) && req_defib)
defib = mainunit
forceMove(defib)
busy = FALSE
update_icon()
/obj/item/twohanded/shockpaddles/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_NO_STORAGE_INSERT, GENERIC_ITEM_TRAIT) //stops shockpaddles from being inserted in BoH
if(!req_defib)
return //If it doesn't need a defib, just say it exists
if (!loc || !istype(loc, /obj/item/defibrillator)) //To avoid weird issues from admin spawns
return INITIALIZE_HINT_QDEL
defib = loc
busy = FALSE
update_icon()
/obj/item/twohanded/shockpaddles/update_icon_state()
icon_state = "[base_icon_state][wielded]"
@@ -397,15 +399,6 @@
forceMove(defib)
defib.update_power()
/obj/item/twohanded/shockpaddles/proc/check_defib_exists(mainunit, mob/living/carbon/M, obj/O)
if(!req_defib)
return TRUE //If it doesn't need a defib, just say it exists
if (!mainunit || !istype(mainunit, /obj/item/defibrillator)) //To avoid weird issues from admin spawns
qdel(O)
return FALSE
else
return TRUE
/obj/item/twohanded/shockpaddles/attack(mob/M, mob/user)
if(busy)
@@ -460,8 +453,6 @@
var/obj/item/organ/heart = H.getorgan(/obj/item/organ/heart)
if(H.suiciding || H.hellbound || HAS_TRAIT(H, TRAIT_HUSK))
return
if((world.time - H.timeofdeath) > tlimit)
return
if((H.getBruteLoss() >= MAX_REVIVE_BRUTE_DAMAGE) || (H.getFireLoss() >= MAX_REVIVE_FIRE_DAMAGE))
return
if(!heart || (heart.organ_flags & ORGAN_FAILING))
@@ -568,7 +559,6 @@
playsound(src, 'sound/machines/defib_charge.ogg', 75, FALSE)
var/total_burn = 0
var/total_brute = 0
var/tplus = world.time - H.timeofdeath //length of time spent dead
var/obj/item/organ/heart = H.getorgan(/obj/item/organ/heart)
if(do_after(user, 20, target = H)) //placed on chest and short delay to shock for dramatic effect, revive time is 5sec total
for(var/obj/item/carried_item in H.contents)
@@ -592,8 +582,6 @@
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Recovery of patient impossible. Further attempts futile.</span>"
else if (H.hellbound)
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's soul appears to be on another plane of existence. Further attempts futile.</span>"
else if (tplus > tlimit)
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Body has decayed for too long. Further attempts futile.</span>"
else if (!heart)
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's heart is missing.</span>"
else if (heart.organ_flags & ORGAN_FAILING)
+2 -2
View File
@@ -533,13 +533,13 @@ GLOBAL_LIST_EMPTY(PDAs)
if("Clear")//Clears messages
tnote = null
if("Ringtone")
var/t = input(U, "Please enter new ringtone", name, ttone) as text|null
var/t = stripped_input(U, "Please enter new ringtone", name, ttone, 20)
if(in_range(src, U) && loc == U && t)
if(SEND_SIGNAL(src, COMSIG_PDA_CHANGE_RINGTONE, U, t) & COMPONENT_STOP_RINGTONE_CHANGE)
U << browse(null, "window=pda")
return
else
ttone = copytext(sanitize(t), 1, 20)
ttone = t
else
U << browse(null, "window=pda")
return
@@ -50,7 +50,7 @@
/obj/item/flashlight/attack(mob/living/carbon/M, mob/living/carbon/human/user)
add_fingerprint(user)
if(istype(M) && on && user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH))
if(istype(M) && on && (user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH)))
if((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50)) //too dumb to use flashlight properly
return ..() //just hit them in the head
@@ -388,7 +388,7 @@
return TRUE
/obj/item/flashlight/emp/attack(mob/living/M, mob/living/user)
if(on && user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH)) // call original attack when examining organs
if(on && (user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH))) // call original attack when examining organs
..()
return
+1 -1
View File
@@ -109,7 +109,7 @@
to_chat(usr,"<span class='warning'>You [transmit_holder ? "enable" : "disable"] your pAI's [transmitting ? "outgoing" : "incoming"] radio transmissions!</span>")
to_chat(pai,"<span class='warning'>Your owner has [transmit_holder ? "enabled" : "disabled"] your [transmitting ? "outgoing" : "incoming"] radio transmissions!</span>")
if(href_list["setlaws"])
var/newlaws = copytext(sanitize(input("Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", pai.laws.supplied[1]) as message|null),1,MAX_MESSAGE_LEN)
var/newlaws = stripped_multiline_input("Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", pai.laws.supplied[1], MAX_MESSAGE_LEN)
if(newlaws && pai)
pai.add_supplied_law(0,newlaws)
if(href_list["toggle_holo"])
@@ -27,6 +27,7 @@
/obj/item/radio/intercom/examine(mob/user)
. = ..()
. += "<span class='notice'>Use [MODE_TOKEN_INTERCOM] when nearby to speak into it.</span>"
if(!unfastened)
. += "<span class='notice'>It's <b>screwed</b> and secured to the wall.</span>"
else
+4 -5
View File
@@ -37,7 +37,7 @@ GENE SCANNER
/obj/item/t_scanner/proc/toggle_on()
on = !on
icon_state = copytext(icon_state, 1, length(icon_state))+"[on]"
icon_state = copytext_char(icon_state, 1, -1) + "[on]"
if(on)
START_PROCESSING(SSobj, src)
else
@@ -320,8 +320,7 @@ GENE SCANNER
if(M.tod && (M.stat == DEAD || ((HAS_TRAIT(M, TRAIT_FAKEDEATH)) && !advanced)))
render_list += "<span class='info ml-1'>Time of Death: [M.tod]</span>\n"
var/tdelta = round(world.time - M.timeofdeath)
if(tdelta < (DEFIB_TIME_LIMIT * 10))
render_list += "<span class='alert ml-1'><b>Subject died [DisplayTimeText(tdelta)] ago, defibrillation may be possible!</b></span>\n"
render_list += "<span class='alert ml-1'><b>Subject died [DisplayTimeText(tdelta)] ago.</b></span>\n"
for(var/thing in M.diseases)
var/datum/disease/D = thing
@@ -734,10 +733,10 @@ GENE SCANNER
if(sequence)
var/display
for(var/i in 0 to length(sequence) / DNA_MUTATION_BLOCKS-1)
for(var/i in 0 to length_char(sequence) / DNA_MUTATION_BLOCKS-1)
if(i)
display += "-"
display += copytext(sequence, 1 + i*DNA_MUTATION_BLOCKS, DNA_MUTATION_BLOCKS*(1+i) + 1)
display += copytext_char(sequence, 1 + i*DNA_MUTATION_BLOCKS, DNA_MUTATION_BLOCKS*(1+i) + 1)
to_chat(user, "<span class='boldnotice'>[display]</span><br>")
@@ -6,6 +6,7 @@
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
custom_price = 1750
custom_premium_price = 1750
/obj/item/sensor_device/attack_self(mob/user)
GLOB.crewmonitor.show(user,src) //Proc already exists, just had to call it
+2 -2
View File
@@ -120,8 +120,8 @@
/obj/item/organ/cyberimp/arm/toolset,
/obj/item/organ/cyberimp/arm/surgery,
/obj/item/organ/cyberimp/chest/thrusters,
/obj/item/organ/lungs/cybernetic/upgraded,
/obj/item/organ/liver/cybernetic/upgraded) //cyberimplants range from a nice bonus to fucking broken bullshit so no subtypesof
/obj/item/organ/lungs/cybernetic/tier3,
/obj/item/organ/liver/cybernetic/tier3) //cyberimplants range from a nice bonus to fucking broken bullshit so no subtypesof
for(var/V in templist)
var/atom/A = V
augment_list[initial(A.name)] = A
+31 -6
View File
@@ -17,7 +17,6 @@
var/active = FALSE
var/atom/movable/target //The thing we're searching for
var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
var/ignore_suit_sensor_level = FALSE // Do we find people even if their suit sensors are turned off
var/alert = FALSE // TRUE to display things more seriously
var/process_scan = TRUE // some pinpointers change target every time they scan, which means we can't have it change very process but instead when it turns on.
var/icon_suffix = "" // for special pinpointer icons
@@ -70,25 +69,31 @@
if(here.z != there.z)
. += "pinon[alert ? "alert" : ""]null[icon_suffix]"
return
. += get_direction_icon(here, there)
///Called by update_icon after sanity. There is a target
/obj/item/pinpointer/proc/get_direction_icon(here, there)
if(get_dist_euclidian(here,there) <= minimum_range)
. += "pinon[alert ? "alert" : ""]direct[icon_suffix]"
return "pinon[alert ? "alert" : ""]direct[icon_suffix]"
else
setDir(get_dir(here, there))
switch(get_dist(here, there))
if(1 to 8)
. += "pinon[alert ? "alert" : "close"][icon_suffix]"
return "pinon[alert ? "alert" : "close"][icon_suffix]"
if(9 to 16)
. += "pinon[alert ? "alert" : "medium"][icon_suffix]"
return "pinon[alert ? "alert" : "medium"][icon_suffix]"
if(16 to INFINITY)
. += "pinon[alert ? "alert" : "far"][icon_suffix]"
return "pinon[alert ? "alert" : "far"][icon_suffix]"
/obj/item/pinpointer/crew // A replacement for the old crew monitoring consoles
name = "crew pinpointer"
desc = "A handheld tracking device that points to crew suit sensors."
icon_state = "pinpointer_crew"
custom_price = 1000
custom_price = 900
custom_premium_price = 900
var/has_owner = FALSE
var/pinpointer_owner = null
var/ignore_suit_sensor_level = FALSE /// Do we find people even if their suit sensors are turned off
/obj/item/pinpointer/crew/proc/trackable(mob/living/carbon/human/H)
var/turf/here = get_turf(src)
@@ -158,6 +163,26 @@
if(!target) //target can be set to null from above code, or elsewhere
active = FALSE
/obj/item/pinpointer/crew/prox //Weaker version of crew monitor primarily for EMT
name = "proximity crew pinpointer"
desc = "A handheld tracking device that displays its proximity to crew suit sensors."
icon_state = "pinpointer_crewprox"
custom_price = 300
/obj/item/pinpointer/crew/prox/get_direction_icon(here, there)
var/size = ""
if(here == there)
size = "small"
else
switch(get_dist(here, there))
if(1 to 4)
size = "xtrlarge"
if(5 to 16)
size = "large"
//17 through 28 use the normal pinion, "pinondirect"
if(29 to INFINITY)
size = "small"
return "pinondirect[size]"
/obj/item/pinpointer/pair
name = "pair pinpointer"
+1
View File
@@ -216,6 +216,7 @@
else if(Kisser.partner == src && !plush_child) //the one advancing does not take ownership of the child and we have a one child policy in the toyshop
user.visible_message("<span class='notice'>[user] is going to break [Kisser] and [src] by bashing them like that.</span>",
"<span class='notice'>[Kisser] passionately embraces [src] in your hands. Look away you perv!</span>")
user.client.give_award(/datum/award/achievement/misc/rule8, user)
if(plop(Kisser))
user.visible_message("<span class='notice'>Something drops at the feet of [user].</span>",
"<span class='notice'>The miracle of oh god did that just come out of [src]?!</span>")
+2 -2
View File
@@ -44,9 +44,9 @@
if(H.stat == DEAD || H == user)
continue
if(H.mind && (has_job_loyalties || has_role_loyalties))
if(has_job_loyalties && H.mind.assigned_role in job_loyalties)
if(has_job_loyalties && (H.mind.assigned_role in job_loyalties))
inspired += H
else if(has_role_loyalties && H.mind.special_role in role_loyalties)
else if(has_role_loyalties && (H.mind.special_role in role_loyalties))
inspired += H
else if(check_inspiration(H))
inspired += H
+16
View File
@@ -89,3 +89,19 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
/obj/item/stack/rods/fifty
amount = 50
/obj/item/stack/rods/lava
name = "heat resistant rod"
desc = "Treated, specialized metal rods. When exposed to the vaccum of space their coating breaks off, but they can hold up against the extreme heat of active lava."
singular_name = "heat resistant rod"
icon_state = "rods"
item_state = "rods"
color = "#5286b9ff"
flags_1 = CONDUCT_1
w_class = WEIGHT_CLASS_NORMAL
custom_materials = list(/datum/material/iron=1000, /datum/material/plasma=500, /datum/material/titanium=2000)
max_amount = 30
resistance_flags = FIRE_PROOF | LAVA_PROOF
/obj/item/stack/rods/lava/thirty
amount = 30
@@ -45,7 +45,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
new/datum/stack_recipe("floor tile", /obj/item/stack/tile/plasteel, 1, 4, 20), \
new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60), \
null, \
new/datum/stack_recipe("wall girders", /obj/structure/girder, 2, time = 40, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("wall girders", /obj/structure/girder, 2, time = 40, one_per_turf = TRUE, on_floor = TRUE, trait_booster = TRAIT_QUICK_BUILD, trait_modifier = 0.75), \
null, \
new/datum/stack_recipe("computer frame", /obj/structure/frame/computer, 5, time = 25, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("modular console", /obj/machinery/modular_computer/console/buildable/, 10, time = 25, one_per_turf = TRUE, on_floor = TRUE), \
@@ -196,6 +196,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
new/datum/stack_recipe("dog bed", /obj/structure/bed/dogbed, 10, time = 10, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 10),\
new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 10),\
new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("wooden buckler", /obj/item/shield/riot/buckler, 20, time = 40), \
new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 50),\
+11 -2
View File
@@ -208,8 +208,13 @@
if(!building_checks(R, multiplier))
return
if (R.time)
var/adjusted_time = 0
usr.visible_message("<span class='notice'>[usr] starts building \a [R.title].</span>", "<span class='notice'>You start building \a [R.title]...</span>")
if (!do_after(usr, R.time, target = usr))
if(HAS_TRAIT(usr, R.trait_booster))
adjusted_time = (R.time * R.trait_modifier)
else
adjusted_time = R.time
if (!do_after(usr, adjusted_time, target = usr))
return
if(!building_checks(R, multiplier))
return
@@ -460,8 +465,10 @@
var/window_checks = FALSE
var/placement_checks = FALSE
var/applies_mats = FALSE
var/trait_booster = null
var/trait_modifier = 1
/datum/stack_recipe/New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1,time = 0, one_per_turf = FALSE, on_floor = FALSE, window_checks = FALSE, placement_checks = FALSE, applies_mats = FALSE)
/datum/stack_recipe/New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1,time = 0, one_per_turf = FALSE, on_floor = FALSE, window_checks = FALSE, placement_checks = FALSE, applies_mats = FALSE, trait_booster = null, trait_modifier = 1)
src.title = title
@@ -475,6 +482,8 @@
src.window_checks = window_checks
src.placement_checks = placement_checks
src.applies_mats = applies_mats
src.trait_booster = trait_booster
src.trait_modifier = trait_modifier
/*
* Recipe list datum
*/
+3 -1
View File
@@ -170,7 +170,9 @@
/obj/item/pinpointer/crew,
/obj/item/holosign_creator/medical,
/obj/item/construction/plumbing,
/obj/item/plunger
/obj/item/plunger,
/obj/item/reagent_containers/spray,
/obj/item/shears
))
/obj/item/storage/belt/medical/paramedic/PopulateContents()
+2 -2
View File
@@ -35,9 +35,9 @@
wielded = 0
if(!isnull(force_unwielded))
force = force_unwielded
var/sf = findtext(name," (Wielded)")
var/sf = findtext(name, " (Wielded)", -10)//10 == length(" (Wielded)")
if(sf)
name = copytext(name,1,sf)
name = copytext(name, 1, sf)
else //something wrong
name = "[initial(name)]"
update_icon()
+120 -17
View File
@@ -1,32 +1,135 @@
/obj/machinery/pinpointer_dispenser
name = "wayfinding pinpointer dispenser"
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "ticketmachine"
desc = "Having trouble finding your way? This machine dispenses pinpointers that point to common locations."
name = "wayfinding pinpointer synthesizer"
icon = 'icons/obj/machines/wayfinding.dmi'
icon_state = "pinpointersynth"
desc = "Having trouble finding your way? This machine synthesizes pinpointers that point to common locations."
density = FALSE
layer = HIGH_OBJ_LAYER
var/list/obj/item/pinpointer/wayfinding/pinpointers = list()
var/spawn_cooldown = 1200 //deciseconds per person to spawn another pinpointer
var/list/user_spawn_cooldowns = list()
var/list/user_interact_cooldowns = list()
var/spawn_cooldown = 5 MINUTES //time per person to spawn another pinpointer
var/interact_cooldown = 20 SECONDS //time per person for subsequent interactions
var/start_bal = 200 //how much money it starts with to cover wayfinder refunds
var/refund_amt = 40 //how much money recycling a pinpointer rewards you
var/datum/bank_account/synth_acc = new /datum/bank_account/remote
var/ppt_cost = 65 //Jan 6 '20: Assistant can buy one roundstart (125 cr starting)
var/expression_timer
/obj/machinery/pinpointer_dispenser/Initialize(mapload)
..()
var/datum/bank_account/civ_acc = SSeconomy.get_dep_account(ACCOUNT_CIV)
if(civ_acc)
synth_acc.transfer_money(civ_acc, start_bal) //float has to come from somewhere, right?
synth_acc.account_holder = name
desc += " Only [ppt_cost] credits! It also likes making costumes..."
set_expression("neutral")
/obj/machinery/pinpointer_dispenser/attack_hand(mob/living/carbon/user)
if(world.time < pinpointers[user.real_name])
var/secsleft = (pinpointers[user.real_name] - world.time) / 10
to_chat(user, "<span class='warning'>You need to wait [secsleft/60 > 1 ? "[round(secsleft/60)] minute\s" : "[round(secsleft)] second\s"].</span>")
if(world.time < user_interact_cooldowns[user.real_name])
to_chat(user, "<span class='warning'>It doesn't respond.</span>")
return
to_chat(user, "<span class='notice'>You take a pinpointer from [src].</span>")
user_interact_cooldowns[user.real_name] = world.time + interact_cooldown
var/obj/item/pinpointer/wayfinding/P = new /obj/item/pinpointer/wayfinding(get_turf(src))
user.put_in_hands(P)
P.owner = user.real_name
pinpointers[user.real_name] = world.time + spawn_cooldown
for(var/obj/item/pinpointer/wayfinding/WP in user.GetAllContents())
set_expression("unsure", 2 SECONDS)
say("<span class='robot'>I can detect the pinpointer on you, [user.first_name()].</span>")
user_spawn_cooldowns[user.real_name] = world.time + spawn_cooldown //spawn timer resets for trickers
return
/obj/item/pinpointer/wayfinding //For new players or new stations to help players find their way around
var/msg
var/dispense = TRUE
var/obj/item/pinpointer/wayfinding/pointat
for(var/obj/item/pinpointer/wayfinding/WP in range(7, user))
if(WP.Adjacent(user))
set_expression("facepalm", 2 SECONDS)
say("<span class='robot'>[WP.owner == user.real_name ? "Your" : "A"] pinpointer is right there.</span>")
pointat(WP)
user_spawn_cooldowns[user.real_name] = world.time + spawn_cooldown
return
else if(WP in oview(7, user))
pointat = WP
break
if(world.time < user_spawn_cooldowns[user.real_name])
var/secsleft = (user_spawn_cooldowns[user.real_name] - world.time) / 10
msg += "to wait another [secsleft/60 > 1 ? "[round(secsleft/60,1)] minute\s" : "[round(secsleft)] second\s"]"
dispense = FALSE
var/datum/bank_account/cust_acc = null
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.get_bank_account())
cust_acc = H.get_bank_account()
if(cust_acc)
if(!cust_acc.has_money(ppt_cost))
msg += "[!msg ? "to find [ppt_cost-cust_acc.account_balance] more credit\s" : " and find [ppt_cost-cust_acc.account_balance] more credit\s"]"
dispense = FALSE
if(!dispense)
set_expression("sad", 2 SECONDS)
if(pointat)
msg += ". I suggest you get [pointat.owner == user.real_name ? "your" : "that"] pinpointer over there instead"
pointat(pointat)
say("<span class='robot'>You will need [msg], [user.first_name()].</span>")
return
if(synth_acc.transfer_money(cust_acc, ppt_cost))
set_expression("veryhappy", 2 SECONDS)
say("<span class='robot'>That is [ppt_cost] credits. Here is your pinpointer.</span>")
var/obj/item/pinpointer/wayfinding/P = new /obj/item/pinpointer/wayfinding(get_turf(src))
user_spawn_cooldowns[user.real_name] = world.time + spawn_cooldown
user.put_in_hands(P)
P.owner = user.real_name
/obj/machinery/pinpointer_dispenser/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/pinpointer/wayfinding))
var/obj/item/pinpointer/wayfinding/WP = I
to_chat(user, "<span class='notice'>You put \the [WP] in the return slot.</span>")
var/rfnd_amt
if((!WP.roundstart || WP.owner != user.real_name) && synth_acc.has_money(TRUE)) //can't recycle own pinpointer for money if not bought; given by a neutral quirk
if(synth_acc.has_money(refund_amt))
rfnd_amt = refund_amt
else
rfnd_amt = synth_acc.account_balance
synth_acc._adjust_money(-rfnd_amt)
var/obj/item/holochip/HC = new /obj/item/holochip(user.loc)
HC.credits = rfnd_amt
HC.name = "[HC.credits] credit holochip"
if(istype(user, /mob/living/carbon/human))
var/mob/living/carbon/human/H = user
H.put_in_hands(HC)
else
var/crap = pick(subtypesof(/obj/effect/spawner/bundle/costume)) //harmless garbage some people may appreciate
new crap(user.loc)
qdel(WP)
set_expression("happy", 2 SECONDS)
say("<span class='robot'>Thank you for recycling, [user.first_name()]! Here is [rfnd_amt ? "[rfnd_amt] credits." : "a freshly synthesized costume!"]</span>")
/obj/machinery/pinpointer_dispenser/proc/set_expression(type, duration)
cut_overlays()
deltimer(expression_timer)
add_overlay(type)
if(duration)
expression_timer = addtimer(CALLBACK(src, .proc/set_expression, "neutral"), duration, TIMER_STOPPABLE)
/obj/machinery/pinpointer_dispenser/proc/pointat(atom)
visible_message("<span class='name'>[src]</span> points at [atom].")
new /obj/effect/temp_visual/point(atom,invisibility)
//Pinpointer itself
/obj/item/pinpointer/wayfinding //Help players new to a station find their way around
name = "wayfinding pinpointer"
desc = "A handheld tracking device that points to useful places."
icon_state = "pinpointer_crew"
icon_state = "pinpointer_way"
resistance_flags = NONE
var/owner = null
var/list/beacons = list()
var/roundstart = FALSE
/obj/item/pinpointer/wayfinding/attack_self(mob/living/user)
if(active)
@@ -70,6 +173,6 @@
if(!target) //target can be set to null from above code, or elsewhere
active = FALSE
//Navbeacon that initialises with wayfinding codes
/obj/machinery/navbeacon/wayfinding
wayfinding = TRUE
+2 -2
View File
@@ -63,8 +63,8 @@
var/flagslist = splittext(set_obj_flags,";")
var/list/string_to_objflag = GLOB.bitfields["obj_flags"]
for (var/flag in flagslist)
if (findtext(flag,"!",1,2))
flag = copytext(flag,1-(length(flag))) // Get all but the initial !
if(flag[1] == "!")
flag = copytext(flag, length(flag[1]) + 1) // Get all but the initial !
obj_flags &= ~string_to_objflag[flag]
else
obj_flags |= string_to_objflag[flag]
+190 -79
View File
@@ -35,101 +35,212 @@
else
painting = null
//////////////
// CANVASES //
//////////////
#define AMT_OF_CANVASES 4 //Keep this up to date or shit will break.
//To safe memory on making /icons we cache the blanks..
GLOBAL_LIST_INIT(globalBlankCanvases, new(AMT_OF_CANVASES))
/obj/item/canvas
name = "canvas"
desc = "Draw out your soul on this canvas!"
icon = 'icons/obj/artstuff.dmi'
icon_state = "11x11"
icon_state = "square"
resistance_flags = FLAMMABLE
var/whichGlobalBackup = 1 //List index
var/width = 11
var/height = 11
var/list/grid
var/list/top_colors
var/canvas_color = "#ffffff" //empty canvas color
var/ui_x = 400
var/ui_y = 400
var/painting_name //Painting name, this is set after framing.
var/framed = FALSE //Blocks edits, set on framing
/obj/item/canvas/nineteenXnineteen
icon_state = "19x19"
whichGlobalBackup = 2
/obj/item/canvas/twentythreeXnineteen
icon_state = "23x19"
whichGlobalBackup = 3
/obj/item/canvas/twentythreeXtwentythree
icon_state = "23x23"
whichGlobalBackup = 4
//HEY YOU
//ARE YOU READING THE CODE FOR CANVASES?
//ARE YOU AWARE THEY CRASH HALF THE SERVER WHEN SOMEONE DRAWS ON THEM...
//...AND NOBODY CAN FIGURE OUT WHY?
//THEN GO ON BRAVE TRAVELER
//TRY TO FIX THEM AND REMOVE THIS CODE
/obj/item/canvas/Initialize()
..()
return INITIALIZE_HINT_QDEL //Delete on creation
. = ..()
top_colors = list()
reset_grid()
//Find the right size blank canvas
/obj/item/canvas/proc/getGlobalBackup()
. = null
if(GLOB.globalBlankCanvases[whichGlobalBackup])
. = GLOB.globalBlankCanvases[whichGlobalBackup]
else
var/icon/I = icon(initial(icon),initial(icon_state))
GLOB.globalBlankCanvases[whichGlobalBackup] = I
. = I
/obj/item/canvas/proc/reset_grid()
grid = new/list(width,height)
for(var/x in 1 to width)
for(var/y in 1 to height)
grid[x][y] = canvas_color
/obj/item/canvas/attack_self(mob/user)
. = ..()
ui_interact(user)
/obj/item/canvas/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
//One pixel increments
/obj/item/canvas/attackby(obj/item/I, mob/user, params)
//Click info
var/list/click_params = params2list(params)
var/pixX = text2num(click_params["icon-x"])
var/pixY = text2num(click_params["icon-y"])
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "canvas", name, ui_x, ui_y, master_ui, state)
ui.set_autoupdate(FALSE)
ui.open()
//Should always be true, otherwise you didn't click the object, but let's check because SS13~
if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
return
//Cleaning one pixel with a soap or rag
if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/glass/rag))
//Pixel info created only when needed
var/icon/masterpiece = icon(icon,icon_state)
var/thePix = masterpiece.GetPixel(pixX,pixY)
var/icon/Ico = getGlobalBackup()
if(!Ico)
qdel(masterpiece)
return
var/theOriginalPix = Ico.GetPixel(pixX,pixY)
if(thePix != theOriginalPix) //colour changed
DrawPixelOn(theOriginalPix,pixX,pixY)
qdel(masterpiece)
//Drawing one pixel with a crayon
else if(istype(I, /obj/item/toy/crayon))
var/obj/item/toy/crayon/C = I
DrawPixelOn(C.paint_color, pixX, pixY)
/obj/item/canvas/attackby(obj/item/I, mob/living/user, params)
if(user.a_intent == INTENT_HELP)
ui_interact(user)
else
return ..()
/obj/item/canvas/ui_data(mob/user)
. = ..()
.["grid"] = grid
.["name"] = painting_name
//Clean the whole canvas
/obj/item/canvas/attack_self(mob/user)
if(!user)
/obj/item/canvas/examine(mob/user)
. = ..()
ui_interact(user)
/obj/item/canvas/ui_act(action, params)
. = ..()
if(. || framed)
return
var/icon/blank = getGlobalBackup()
if(blank)
//it's basically a giant etch-a-sketch
icon = blank
user.visible_message("<span class='notice'>[user] cleans the canvas.</span>","<span class='notice'>You clean the canvas.</span>")
var/mob/user = usr
switch(action)
if("paint")
var/obj/item/I = user.get_active_held_item()
var/color = get_paint_tool_color(I)
if(!color)
return FALSE
var/x = text2num(params["x"])
var/y = text2num(params["y"])
grid[x][y] = color
top_colors = get_most_common_colors(3)
update_icon()
. = TRUE
/obj/item/canvas/update_overlays()
. = ..()
for(var/i in 2 to top_colors.len) //first is used as base color
var/mutable_appearance/detail = mutable_appearance(icon, "[icon_state]_detail_[i-1]")
detail.appearance_flags |= RESET_COLOR
detail.color = top_colors[i]
. += detail
/obj/item/canvas/update_icon_state()
. = ..()
if(top_colors.len)
color = top_colors[1]
/obj/item/canvas/proc/get_most_common_colors(count)
var/list/tally = list()
for(var/x in 1 to width)
for(var/y in 1 to height)
tally[grid[x][y]] += 1
sortTim(tally,/proc/cmp_numeric_dsc,associative=TRUE)
. = list()
for(var/result in tally)
. += result
if(length(.) >= count)
break
//Todo make this element ?
/obj/item/canvas/proc/get_paint_tool_color(obj/item/I)
if(!I)
return
if(istype(I, /obj/item/toy/crayon))
var/obj/item/toy/crayon/C = I
return C.paint_color
else if(istype(I, /obj/item/pen))
var/obj/item/pen/P = I
switch(P.colour)
if("black")
return "#000000"
if("blue")
return "#0000ff"
if("red")
return "#ff0000"
return P.colour
else if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/glass/rag))
return canvas_color
/obj/item/canvas/nineteenXnineteen
icon_state = "square"
width = 19
height = 19
ui_x = 600
ui_y = 600
/obj/item/canvas/twentythreeXnineteen
icon_state = "wide"
width = 23
height = 19
ui_x = 800
ui_y = 600
/obj/item/canvas/twentythreeXtwentythree
icon_state = "square"
width = 23
height = 23
ui_x = 800
ui_y = 800
#undef AMT_OF_CANVASES
/obj/item/wallframe/painting
name = "painting frame"
desc = "The perfect showcase for your favorite deathtrap memories."
icon = 'icons/obj/decals.dmi'
custom_materials = null
flags_1 = 0
icon_state = "frame-empty"
result_path = /obj/structure/sign/painting
/obj/structure/sign/painting
name = "Painting"
desc = "Art or \"Art\"? You decide."
icon = 'icons/obj/decals.dmi'
icon_state = "frame-empty"
buildable_sign = FALSE
var/obj/item/canvas/C
/obj/structure/sign/painting/Initialize(mapload, dir, building)
. = ..()
AddComponent(/datum/component/art, 20)
if(dir)
setDir(dir)
if(building)
pixel_x = (dir & 3)? 0 : (dir == 4 ? -30 : 30)
pixel_y = (dir & 3)? (dir ==1 ? -30 : 30) : 0
/obj/structure/sign/painting/attackby(obj/item/I, mob/user, params)
if(!C && istype(I, /obj/item/canvas))
frame_canvas(user,I)
else if(C && !C.painting_name && istype(I,/obj/item/pen))
try_rename(user)
else
return ..()
/obj/structure/sign/painting/examine(mob/user)
. = ..()
if(C)
C.ui_interact(user,state = GLOB.physical_obscured_state)
/obj/structure/sign/painting/wirecutter_act(mob/living/user, obj/item/I)
. = ..()
if(C)
C.framed = FALSE
C.forceMove(drop_location())
C = null
to_chat(user, "<span class='notice'>You remove the painting from the frame.</span>")
update_icon()
return TRUE
/obj/structure/sign/painting/proc/frame_canvas(mob/user,obj/item/canvas/new_canvas)
if(user.transferItemToLoc(new_canvas,src))
C = new_canvas
C.framed = TRUE
to_chat(user,"<span class='notice'>You frame [C].</span>")
update_icon()
/obj/structure/sign/painting/proc/try_rename(mob/user)
var/new_name = stripped_input(user,"What do you want to name the painting?")
if(C && !C.painting_name && new_name && user.canUseTopic(src,BE_CLOSE))
C.painting_name = new_name
SStgui.update_uis(C)
/obj/structure/sign/painting/update_overlays()
. = ..()
if(C && C.top_colors.len)
var/mutable_appearance/MA = mutable_appearance(icon, "frame-content-overlay")
MA.appearance_flags |= RESET_COLOR
MA.color = C.top_colors[1]
. += MA
+11 -4
View File
@@ -7,6 +7,7 @@
var/state = GIRDER_NORMAL
var/girderpasschance = 20 // percentage chance that a projectile passes through the girder.
var/can_displace = TRUE //If the girder can be moved around by wrenching it
var/next_beep = 0 //Prevents spamming of the construction sound
max_integrity = 200
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
rad_insulation = RAD_VERY_LIGHT_INSULATION
@@ -27,6 +28,12 @@
. += "<span class='notice'>[src] is disassembled! You probably shouldn't be able to see this examine message.</span>"
/obj/structure/girder/attackby(obj/item/W, mob/user, params)
var/platingmodifier = 1
if(HAS_TRAIT(user, TRAIT_QUICK_BUILD))
platingmodifier = 0.7
if(next_beep <= world.time)
next_beep = world.time + 10
playsound(src, 'sound/machines/clockcult/integration_cog_install.ogg', 50, TRUE)
add_fingerprint(user)
if(istype(W, /obj/item/gun/energy/plasmacutter))
@@ -89,7 +96,7 @@
to_chat(user, "<span class='warning'>You need two sheets of metal to create a false wall!</span>")
return
to_chat(user, "<span class='notice'>You start building a false wall...</span>")
if(do_after(user, 20, target = src))
if(do_after(user, 20*platingmodifier, target = src))
if(S.get_amount() < 2)
return
S.use(2)
@@ -102,7 +109,7 @@
to_chat(user, "<span class='warning'>You need two sheets of metal to finish a wall!</span>")
return
to_chat(user, "<span class='notice'>You start adding plating...</span>")
if (do_after(user, 40, target = src))
if (do_after(user, 40*platingmodifier, target = src))
if(S.get_amount() < 2)
return
S.use(2)
@@ -132,7 +139,7 @@
if(S.get_amount() < 1)
return
to_chat(user, "<span class='notice'>You start finalizing the reinforced wall...</span>")
if(do_after(user, 50, target = src))
if(do_after(user, 50*platingmodifier, target = src))
if(S.get_amount() < 1)
return
S.use(1)
@@ -146,7 +153,7 @@
if(S.get_amount() < 1)
return
to_chat(user, "<span class='notice'>You start reinforcing the girder...</span>")
if(do_after(user, 60, target = src))
if(do_after(user, 60*platingmodifier, target = src))
if(S.get_amount() < 1)
return
S.use(1)
+3 -2
View File
@@ -41,8 +41,9 @@
if(.)
return
to_chat(user, "<span class='notice'>You take down [src].</span>")
victim.forceMove(drop_location())
victim = null
if(victim)
victim.forceMove(drop_location())
victim = null
spear.forceMove(drop_location())
spear = null
qdel(src)
+28 -1
View File
@@ -74,7 +74,7 @@
number_of_rods = 2
smooth = SMOOTH_TRUE
canSmoothWith = null
obj_flags = CAN_BE_HIT | BLOCK_Z_FALL
obj_flags = CAN_BE_HIT | BLOCK_Z_FALL
/obj/structure/lattice/catwalk/deconstruction_hints(mob/user)
return "<span class='notice'>The supporting rods look like they could be <b>cut</b>.</span>"
@@ -90,3 +90,30 @@
for(var/obj/structure/cable/C in T)
C.deconstruct()
..()
/obj/structure/lattice/lava
name = "heatproof support lattice"
desc = "A specialized support beam for building across lava. Watch your step."
icon = 'icons/obj/smooth_structures/catwalk.dmi'
icon_state = "catwalk"
number_of_rods = 1
color = "#5286b9ff"
smooth = SMOOTH_TRUE
canSmoothWith = null
obj_flags = CAN_BE_HIT | BLOCK_Z_FALL
resistance_flags = FIRE_PROOF | LAVA_PROOF
/obj/structure/lattice/lava/deconstruction_hints(mob/user)
return "<span class='notice'>The rods look like they could be <b>cut</b>, but the <i>heat treatment will shatter off</i>. There's space for a <i>tile</i>.</span>"
/obj/structure/lattice/lava/attackby(obj/item/C, mob/user, params)
. = ..()
if(istype(C, /obj/item/stack/tile/plasteel))
var/obj/item/stack/tile/plasteel/P = C
if(P.use(1))
to_chat(user, "<span class='notice'>You construct a floor plating, as lava settles around the rods.</span>")
playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE)
new /turf/open/floor/plating(locate(x, y, z))
else
to_chat(user, "<span class='warning'>You need one floor tile to build atop [src].</span>")
return
+1 -2
View File
@@ -136,8 +136,7 @@
switch(choice)
if("name")
var/newname = copytext(sanitize_name(reject_bad_text(input(H, "Who are we again?", "Name change", H.name) as null|text)),1,MAX_NAME_LEN)
var/newname = sanitize_name(reject_bad_text(stripped_input(H, "Who are we again?", "Name change", H.name, MAX_NAME_LEN)))
if(!newname)
return
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
+1 -1
View File
@@ -181,7 +181,7 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an
icon_state = "morgue1"
else
icon_state = "morgue2" // Dead, brainded mob.
var/list/compiled = recursive_mob_check(src, 0, 0) // Search for mobs in all contents.
var/list/compiled = GetAllContents(/mob/living) // Search for mobs in all contents.
if(!length(compiled)) // No mobs?
icon_state = "morgue3"
return
+12 -11
View File
@@ -112,8 +112,10 @@
var/cur_note = text2ascii(note) - 96
if(cur_note < 1 || cur_note > 7)
continue
for(var/i=2 to length(note))
var/ni = copytext(note,i,i+1)
var/notelen = length(note)
var/ni = ""
for(var/i = length(note[1]) + 1, i <= notelen, i += length(ni))
ni = note[i]
if(!text2num(ni))
if(ni == "#" || ni == "b" || ni == "n")
cur_acc[cur_note] = ni
@@ -202,9 +204,10 @@
//split into lines
lines = splittext(text, "\n")
if(lines.len)
if(copytext(lines[1],1,6) == "BPM: ")
tempo = sanitize_tempo(600 / text2num(copytext(lines[1],6)))
lines.Cut(1,2)
var/bpm_string = "BPM: "
if(findtext(lines[1], bpm_string, 1, length(bpm_string) + 1))
tempo = sanitize_tempo(600 / text2num(copytext(lines[1], length(bpm_string) + 1)))
lines.Cut(1, 2)
else
tempo = sanitize_tempo(5) // default 120 BPM
if(lines.len > MUSIC_MAXLINES)
@@ -212,7 +215,7 @@
lines.Cut(MUSIC_MAXLINES + 1)
var/linenum = 1
for(var/l in lines)
if(length(l) > MUSIC_MAXLINECHARS)
if(length_char(l) > MUSIC_MAXLINECHARS)
to_chat(usr, "Line [linenum] too long!")
lines.Remove(l)
else
@@ -276,8 +279,8 @@
return
if(lines.len > MUSIC_MAXLINES)
return
if(length(newline) > MUSIC_MAXLINECHARS)
newline = copytext(newline, 1, MUSIC_MAXLINECHARS)
if(length_char(newline) > MUSIC_MAXLINECHARS)
newline = copytext_char(newline, 1, MUSIC_MAXLINECHARS)
lines.Add(newline)
else if(href_list["deleteline"])
@@ -288,11 +291,9 @@
else if(href_list["modifyline"])
var/num = round(text2num(href_list["modifyline"]),1)
var/content = html_encode(input("Enter your line: ", instrumentObj.name, lines[num]) as text|null)
var/content = stripped_input(usr, "Enter your line: ", instrumentObj.name, lines[num], MUSIC_MAXLINECHARS)
if(!content || !usr.canUseTopic(instrumentObj, BE_CLOSE, FALSE, NO_TK))
return
if(length(content) > MUSIC_MAXLINECHARS)
content = copytext(content, 1, MUSIC_MAXLINECHARS)
if(num > lines.len || num < 1)
return
lines[num] = content
+1 -1
View File
@@ -39,7 +39,7 @@
. = ..()
if(!isliving(user))
return
if(user.mind && user.mind in immune_minds)
if(user.mind && (user.mind in immune_minds))
return
if(get_dist(user, src) <= 1)
. += "<span class='notice'>You reveal [src]!</span>"