mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-25 22:19:30 +01:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),\
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>"
|
||||
|
||||
Reference in New Issue
Block a user