mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-12 07:33:34 +01:00
fixes merge conflict, updates to master
This commit is contained in:
@@ -221,6 +221,12 @@
|
||||
A.contents += thing
|
||||
thing.change_area(old_area, A)
|
||||
|
||||
var/area/oldA = get_area(get_turf(usr))
|
||||
var/list/firedoors = oldA.firedoors
|
||||
for(var/door in firedoors)
|
||||
var/obj/machinery/door/firedoor/FD = door
|
||||
FD.CalculateAffectingAreas()
|
||||
|
||||
interact()
|
||||
area_created = TRUE
|
||||
return area_created
|
||||
@@ -236,6 +242,10 @@
|
||||
return
|
||||
set_area_machinery_title(A,str,prevname)
|
||||
A.name = str
|
||||
if(A.firedoors)
|
||||
for(var/D in A.firedoors)
|
||||
var/obj/machinery/door/firedoor/FD = D
|
||||
FD.CalculateAffectingAreas()
|
||||
to_chat(usr, "<span class='notice'>You rename the '[prevname]' to '[str]'.</span>")
|
||||
interact()
|
||||
return 1
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
//copy pasta of the space piano, don't hurt me -Pete
|
||||
/obj/item/instrument
|
||||
name = "generic instrument"
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
lefthand_file = 'icons/mob/inhands/equipment/instruments_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/instruments_righthand.dmi'
|
||||
resistance_flags = FLAMMABLE
|
||||
max_integrity = 100
|
||||
var/datum/song/handheld/song
|
||||
var/instrumentId = "generic"
|
||||
var/instrumentExt = "mid"
|
||||
|
||||
/obj/item/instrument/New()
|
||||
song = new(instrumentId, src, instrumentExt)
|
||||
..()
|
||||
|
||||
/obj/item/instrument/Destroy()
|
||||
QDEL_NULL(song)
|
||||
return ..()
|
||||
|
||||
/obj/item/instrument/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] begins to play 'Gloomy Sunday'! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return BRUTELOSS
|
||||
|
||||
/obj/item/instrument/Initialize(mapload)
|
||||
song.tempo = song.sanitize_tempo(song.tempo) // tick_lag isn't set when the map is loaded
|
||||
..()
|
||||
|
||||
/obj/item/instrument/attack_self(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/instrument/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
if(!isliving(user) || user.incapacitated())
|
||||
return
|
||||
|
||||
song.ui_interact(user, ui_key, ui, force_open)
|
||||
|
||||
/obj/item/instrument/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
return song.ui_data(user, ui_key, state)
|
||||
|
||||
/obj/item/instrument/Topic(href, href_list)
|
||||
song.Topic(href, href_list)
|
||||
|
||||
/obj/item/instrument/violin
|
||||
name = "space violin"
|
||||
desc = "A wooden musical instrument with four strings and a bow. \"The devil went down to space, he was looking for an assistant to grief.\""
|
||||
icon_state = "violin"
|
||||
item_state = "violin"
|
||||
instrumentExt = "ogg"
|
||||
force = 10
|
||||
hitsound = "swing_hit"
|
||||
instrumentId = "violin"
|
||||
|
||||
/obj/item/instrument/violin/golden
|
||||
name = "golden violin"
|
||||
desc = "A golden musical instrument with four strings and a bow. \"The devil went down to space, he was looking for an assistant to grief.\""
|
||||
icon_state = "golden_violin"
|
||||
item_state = "golden_violin"
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
|
||||
/obj/item/instrument/piano_synth
|
||||
name = "synthesizer"
|
||||
desc = "An advanced electronic synthesizer that can be used as various instruments."
|
||||
icon_state = "synth"
|
||||
item_state = "synth"
|
||||
instrumentId = "piano"
|
||||
instrumentExt = "ogg"
|
||||
var/static/list/insTypes = list("accordion" = "mid", "glockenspiel" = "mid", "guitar" = "ogg", "eguitar" = "ogg", "harmonica" = "mid", "piano" = "ogg", "recorder" = "mid", "saxophone" = "mid", "trombone" = "mid", "violin" = "ogg", "xylophone" = "mid")
|
||||
actions_types = list(/datum/action/item_action/synthswitch)
|
||||
|
||||
/obj/item/instrument/piano_synth/proc/changeInstrument(name = "piano")
|
||||
song.instrumentDir = name
|
||||
song.instrumentExt = insTypes[name]
|
||||
|
||||
/obj/item/instrument/guitar
|
||||
name = "guitar"
|
||||
desc = "It's made of wood and has bronze strings."
|
||||
icon_state = "guitar"
|
||||
item_state = "guitar"
|
||||
instrumentExt = "ogg"
|
||||
force = 10
|
||||
attack_verb = list("played metal on", "serenaded", "crashed", "smashed")
|
||||
hitsound = 'sound/effects/guitarsmash.ogg'
|
||||
instrumentId = "guitar"
|
||||
|
||||
/obj/item/instrument/eguitar
|
||||
name = "electric guitar"
|
||||
desc = "Makes all your shredding needs possible."
|
||||
icon_state = "eguitar"
|
||||
item_state = "eguitar"
|
||||
instrumentExt = "ogg"
|
||||
force = 12
|
||||
attack_verb = list("played metal on", "shredded", "crashed", "smashed")
|
||||
hitsound = 'sound/weapons/stringsmash.ogg'
|
||||
instrumentId = "eguitar"
|
||||
|
||||
/obj/item/instrument/glockenspiel
|
||||
name = "glockenspiel"
|
||||
desc = "Smooth metal bars perfect for any marching band."
|
||||
icon_state = "glockenspiel"
|
||||
item_state = "glockenspiel"
|
||||
instrumentId = "glockenspiel"
|
||||
|
||||
/obj/item/instrument/accordion
|
||||
name = "accordion"
|
||||
desc = "Pun-Pun not included."
|
||||
icon_state = "accordion"
|
||||
item_state = "accordion"
|
||||
instrumentId = "accordion"
|
||||
|
||||
/obj/item/instrument/saxophone
|
||||
name = "saxophone"
|
||||
desc = "This soothing sound will be sure to leave your audience in tears."
|
||||
icon_state = "saxophone"
|
||||
item_state = "saxophone"
|
||||
instrumentId = "saxophone"
|
||||
|
||||
/obj/item/instrument/trombone
|
||||
name = "trombone"
|
||||
desc = "How can any pool table ever hope to compete?"
|
||||
icon_state = "trombone"
|
||||
item_state = "trombone"
|
||||
instrumentId = "trombone"
|
||||
|
||||
/obj/item/instrument/recorder
|
||||
name = "recorder"
|
||||
desc = "Just like in school, playing ability and all."
|
||||
icon_state = "recorder"
|
||||
item_state = "recorder"
|
||||
instrumentId = "recorder"
|
||||
|
||||
/obj/item/instrument/harmonica
|
||||
name = "harmonica"
|
||||
desc = "For when you get a bad case of the space blues."
|
||||
icon_state = "harmonica"
|
||||
item_state = "harmonica"
|
||||
instrumentId = "harmonica"
|
||||
force = 5
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/instrument/xylophone
|
||||
name = "xylophone"
|
||||
desc = "a percussion instrument with a bright tone."
|
||||
icon_state = "xylophone"
|
||||
item_state = "xylophone"
|
||||
instrumentId = "xylophone"
|
||||
|
||||
/obj/item/instrument/bikehorn
|
||||
name = "gilded bike horn"
|
||||
desc = "An exquisitely decorated bike horn, capable of honking in a variety of notes."
|
||||
icon_state = "bike_horn"
|
||||
item_state = "bike_horn"
|
||||
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
|
||||
attack_verb = list("beautifully honks")
|
||||
instrumentId = "bikehorn"
|
||||
instrumentExt = "ogg"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
force = 0
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
hitsound = 'sound/items/bikehorn.ogg'
|
||||
|
||||
/datum/crafting_recipe/violin
|
||||
name = "Violin"
|
||||
result = /obj/item/instrument/violin
|
||||
reqs = list(/obj/item/stack/sheet/wood = 5,
|
||||
/obj/item/stack/cable_coil = 6,
|
||||
/obj/item/stack/tape_roll = 5)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
|
||||
time = 80
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/guitar
|
||||
name = "Guitar"
|
||||
result = /obj/item/instrument/guitar
|
||||
reqs = list(/obj/item/stack/sheet/wood = 5,
|
||||
/obj/item/stack/cable_coil = 6,
|
||||
/obj/item/stack/tape_roll = 5)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
|
||||
time = 80
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/eguitar
|
||||
name = "Electric Guitar"
|
||||
result = /obj/item/instrument/eguitar
|
||||
reqs = list(/obj/item/stack/sheet/metal = 5,
|
||||
/obj/item/stack/cable_coil = 6,
|
||||
/obj/item/stack/tape_roll = 5)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
|
||||
time = 80
|
||||
category = CAT_MISC
|
||||
@@ -186,10 +186,10 @@
|
||||
update_icon()
|
||||
START_PROCESSING(SSobj, src)
|
||||
for(var/i, i<= 5, i++)
|
||||
wires.UpdateCut(i,1)
|
||||
wires.on_cut(i, 1)
|
||||
|
||||
/obj/item/radio/intercom/wirecutter_act(mob/user, obj/item/I)
|
||||
if(!(buildstage == 3 && b_stat && wires.IsAllCut()))
|
||||
if(!(buildstage == 3 && b_stat && wires.is_all_cut()))
|
||||
return
|
||||
. = TRUE
|
||||
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
|
||||
@@ -270,4 +270,4 @@
|
||||
|
||||
/obj/item/radio/intercom/locked/prison/New()
|
||||
..()
|
||||
wires.CutWireIndex(RADIO_WIRE_TRANSMIT)
|
||||
wires.cut(WIRE_RADIO_TRANSMIT)
|
||||
|
||||
@@ -76,6 +76,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
|
||||
GLOB.global_radios |= src
|
||||
|
||||
/obj/item/radio/Destroy()
|
||||
SStgui.close_uis(wires)
|
||||
QDEL_NULL(wires)
|
||||
if(SSradio)
|
||||
SSradio.remove_object(src, frequency)
|
||||
@@ -127,8 +128,8 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
|
||||
data["freq"] = format_frequency(frequency)
|
||||
data["rawfreq"] = num2text(frequency)
|
||||
|
||||
data["mic_cut"] = (wires.IsIndexCut(RADIO_WIRE_TRANSMIT) || wires.IsIndexCut(RADIO_WIRE_SIGNAL))
|
||||
data["spk_cut"] = (wires.IsIndexCut(RADIO_WIRE_RECEIVE) || wires.IsIndexCut(RADIO_WIRE_SIGNAL))
|
||||
data["mic_cut"] = (wires.is_cut(WIRE_RADIO_TRANSMIT) || wires.is_cut(WIRE_RADIO_SIGNAL))
|
||||
data["spk_cut"] = (wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL))
|
||||
|
||||
var/list/chanlist = list_channels(user)
|
||||
if(islist(chanlist) && chanlist.len)
|
||||
@@ -184,10 +185,10 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
|
||||
return can_admin_interact()
|
||||
|
||||
/obj/item/radio/proc/ToggleBroadcast()
|
||||
broadcasting = !broadcasting && !(wires.IsIndexCut(RADIO_WIRE_TRANSMIT) || wires.IsIndexCut(RADIO_WIRE_SIGNAL))
|
||||
broadcasting = !broadcasting && !(wires.is_cut(WIRE_RADIO_TRANSMIT) || wires.is_cut(WIRE_RADIO_SIGNAL))
|
||||
|
||||
/obj/item/radio/proc/ToggleReception()
|
||||
listening = !listening && !(wires.IsIndexCut(RADIO_WIRE_RECEIVE) || wires.IsIndexCut(RADIO_WIRE_SIGNAL))
|
||||
listening = !listening && !(wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL))
|
||||
|
||||
/obj/item/radio/Topic(href, href_list)
|
||||
if(..())
|
||||
@@ -334,7 +335,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
|
||||
|
||||
// Uncommenting this. To the above comment:
|
||||
// The permacell radios aren't suppose to be able to transmit, this isn't a bug and this "fix" is just making radio wires useless. -Giacom
|
||||
if(wires.IsIndexCut(RADIO_WIRE_TRANSMIT)) // The device has to have all its wires and shit intact
|
||||
if(wires.is_cut(WIRE_RADIO_TRANSMIT)) // The device has to have all its wires and shit intact
|
||||
return 0
|
||||
|
||||
if(!M.IsVocal())
|
||||
@@ -515,7 +516,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
|
||||
var/is_listening = TRUE
|
||||
if(!on)
|
||||
is_listening = FALSE
|
||||
if(!wires || wires.IsIndexCut(RADIO_WIRE_RECEIVE))
|
||||
if(!wires || wires.is_cut(WIRE_RADIO_RECEIVER))
|
||||
is_listening = FALSE
|
||||
if(!listening)
|
||||
is_listening = FALSE
|
||||
|
||||
@@ -72,8 +72,7 @@ REAGENT SCANNER
|
||||
var/turf/U = O.loc
|
||||
if(U && U.intact)
|
||||
O.invisibility = 101
|
||||
if(O)
|
||||
O.alpha = 255
|
||||
O.alpha = 255
|
||||
for(var/mob/living/M in T.contents)
|
||||
var/oldalpha = M.alpha
|
||||
if(M.alpha < 255 && istype(M))
|
||||
|
||||
@@ -251,6 +251,7 @@
|
||||
message_admins("[key_name_admin(user)] has lit the [src] trapped with [boobytrap] by [key_name_admin(trapper)] at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a>.")
|
||||
log_game("[key_name_admin(user)] has lit the [src] trapped with [boobytrap] by [key_name_admin(trapper)] at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).")
|
||||
investigate_log("[key_name_admin(user)] has lit the [src] trapped with [boobytrap] by [key_name_admin(trapper)] at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).", INVESTIGATE_BOMB)
|
||||
burn()
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -267,8 +268,16 @@
|
||||
|
||||
/obj/item/flag/chameleon/burn()
|
||||
if(boobytrap)
|
||||
boobytrap.prime()
|
||||
..()
|
||||
fire_act()
|
||||
addtimer(CALLBACK(src, .proc/prime_boobytrap), boobytrap.det_time)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/flag/chameleon/proc/prime_boobytrap()
|
||||
boobytrap.forceMove(get_turf(loc))
|
||||
boobytrap.prime()
|
||||
boobytrap = null
|
||||
burn()
|
||||
|
||||
/obj/item/flag/chameleon/updateFlagIcon()
|
||||
icon_state = updated_icon_state
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
playsound(src.loc, 'sound/weapons/cablecuff.ogg', 15, 1, -1)
|
||||
|
||||
M.visible_message("<span class='danger'>[U] comes from behind and begins garroting [M] with the [src]!</span>", \
|
||||
"<span class='userdanger'>[U]\ begins garroting you with the [src]![improvised ? "" : " You are unable to speak!"]</span>", \
|
||||
"<span class='userdanger'>[U] begins garroting you with the [src]![improvised ? "" : " You are unable to speak!"]</span>", \
|
||||
"You hear struggling and wire strain against flesh!")
|
||||
|
||||
return
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
/obj/item/grenade/smokebomb/prime()
|
||||
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
|
||||
src.smoke.set_up(10, 0, usr.loc)
|
||||
smoke.set_up(10, 0)
|
||||
spawn(0)
|
||||
src.smoke.start()
|
||||
sleep(10)
|
||||
|
||||
@@ -372,6 +372,15 @@
|
||||
new /obj/item/ammo_box/magazine/m12g/buckshot(src)
|
||||
new /obj/item/ammo_box/magazine/m12g/dragon(src)
|
||||
|
||||
/obj/item/storage/backpack/duffel/syndie/ammo/shotgunXLmags
|
||||
desc = "A large duffelbag, containing three types of extended drum magazines."
|
||||
|
||||
/obj/item/storage/backpack/duffel/syndie/ammo/shotgunXLmags/New()
|
||||
..()
|
||||
new /obj/item/ammo_box/magazine/m12g/XtrLrg(src)
|
||||
new /obj/item/ammo_box/magazine/m12g/XtrLrg/buckshot(src)
|
||||
new /obj/item/ammo_box/magazine/m12g/XtrLrg/dragon(src)
|
||||
|
||||
/obj/item/storage/backpack/duffel/mining_conscript/
|
||||
name = "mining conscription kit"
|
||||
desc = "A kit containing everything a crewmember needs to support a shaft miner in the field."
|
||||
|
||||
@@ -380,12 +380,13 @@
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
flags = CONDUCT
|
||||
materials = list(MAT_METAL=3000)
|
||||
cant_hold = list(/obj/item/disk/nuclear) // Prevents some cheesing
|
||||
|
||||
/obj/item/storage/bag/tray/attack(mob/living/M as mob, mob/living/user as mob)
|
||||
/obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user)
|
||||
..()
|
||||
// Drop all the things. All of them.
|
||||
var/list/obj/item/oldContents = contents.Copy()
|
||||
quick_empty()
|
||||
drop_inventory(user)
|
||||
|
||||
// Make each item scatter a bit
|
||||
for(var/obj/item/I in oldContents)
|
||||
|
||||
@@ -438,8 +438,11 @@
|
||||
if((!ishuman(usr) && (src.loc != usr)) || usr.stat || usr.restrained())
|
||||
return
|
||||
|
||||
drop_inventory(usr)
|
||||
|
||||
/obj/item/storage/proc/drop_inventory(user)
|
||||
var/turf/T = get_turf(src)
|
||||
hide_from(usr)
|
||||
hide_from(user)
|
||||
for(var/obj/item/I in contents)
|
||||
remove_from_storage(I, T)
|
||||
CHECK_TICK
|
||||
@@ -499,10 +502,9 @@
|
||||
|
||||
/obj/item/storage/attack_self(mob/user)
|
||||
|
||||
//Clicking on itself will empty it, if it has the verb to do that.
|
||||
if(user.is_in_active_hand(src))
|
||||
if(verbs.Find(/obj/item/storage/verb/quick_empty))
|
||||
quick_empty()
|
||||
//Clicking on itself will empty it, if allow_quick_empty is TRUE
|
||||
if(allow_quick_empty && user.is_in_active_hand(src))
|
||||
drop_inventory(user)
|
||||
|
||||
//Returns the storage depth of an atom. This is the number of storage items the atom is contained in before reaching toplevel (the area).
|
||||
//Returns -1 if the atom was not found on container.
|
||||
|
||||
@@ -43,35 +43,31 @@
|
||||
/obj/item/tank/proc/toggle_internals(mob/user, silent = FALSE)
|
||||
var/mob/living/carbon/C = user
|
||||
if(!istype(C))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(C.internal == src)
|
||||
to_chat(C, "<span class='notice'>You close \the [src] valve.</span>")
|
||||
C.internal = null
|
||||
else
|
||||
var/can_open_valve = 0
|
||||
if(C.get_organ_slot("breathing_tube"))
|
||||
can_open_valve = 1
|
||||
else if(C.wear_mask && C.wear_mask.flags & AIRTIGHT)
|
||||
can_open_valve = 1
|
||||
else if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(H.head && H.head.flags & AIRTIGHT)
|
||||
can_open_valve = 1
|
||||
if(!C.get_organ_slot("breathing_tube")) // Breathing tubes can always use internals, if they have one, skip ahead and turn internals on/off
|
||||
if(!C.wear_mask) // Do we have a mask equipped?
|
||||
return FALSE
|
||||
|
||||
if(can_open_valve)
|
||||
var/obj/item/clothing/mask/M = C.wear_mask
|
||||
// If the "mask" isn't actually a mask OR That mask isn't internals compatible AND Their headgear isn't internals compatible
|
||||
if(!istype(M) || (!(initial(M.flags) & AIRTIGHT) && !(C.head.flags & AIRTIGHT)))
|
||||
if(!silent)
|
||||
to_chat(C, "<span class='warning'>You are not wearing a suitable mask or helmet.</span>")
|
||||
return FALSE
|
||||
if(M.mask_adjusted) // If the mask is equipped but pushed down
|
||||
M.adjustmask(C) // Adjust it back
|
||||
|
||||
if(!silent)
|
||||
if(C.internal)
|
||||
if(!silent)
|
||||
to_chat(C, "<span class='notice'>You switch your internals to [src].</span>")
|
||||
to_chat(C, "<span class='notice'>You switch your internals to [src].</span>")
|
||||
else
|
||||
if(!silent)
|
||||
to_chat(C, "<span class='notice'>You open \the [src] valve.</span>")
|
||||
C.internal = src
|
||||
else
|
||||
if(!silent)
|
||||
to_chat(C, "<span class='notice'>You are not wearing a suitable mask or helmet.</span>")
|
||||
return 0
|
||||
|
||||
to_chat(C, "<span class='notice'>You open \the [src] valve.</span>")
|
||||
C.internal = src
|
||||
C.update_action_buttons_icon()
|
||||
|
||||
|
||||
|
||||
@@ -45,8 +45,6 @@
|
||||
new /obj/item/clothing/suit/storage/labcoat(src)
|
||||
new /obj/item/radio/headset/headset_sci(src)
|
||||
new /obj/item/radio/headset/headset_sci(src)
|
||||
new /obj/item/reagent_containers/food/drinks/oilcan(src)
|
||||
new /obj/item/reagent_containers/food/drinks/oilcan(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/RD
|
||||
name = "research director's locker"
|
||||
|
||||
@@ -1,341 +0,0 @@
|
||||
|
||||
|
||||
/datum/song
|
||||
var/name = "Untitled"
|
||||
var/list/lines = new()
|
||||
var/tempo = 5 // delay between notes
|
||||
|
||||
var/playing = 0 // if we're playing
|
||||
var/help = 0 // if help is open
|
||||
var/repeat = 0 // number of times remaining to repeat
|
||||
var/max_repeat = 10 // maximum times we can repeat
|
||||
|
||||
var/instrumentDir = "piano" // the folder with the sounds
|
||||
var/instrumentExt = "ogg" // the file extension
|
||||
var/obj/instrumentObj = null // the associated obj playing the sound
|
||||
|
||||
/datum/song/New(dir, obj, ext = "ogg")
|
||||
tempo = sanitize_tempo(tempo)
|
||||
instrumentDir = dir
|
||||
instrumentObj = obj
|
||||
instrumentExt = ext
|
||||
|
||||
/datum/song/Destroy()
|
||||
instrumentObj = null
|
||||
return ..()
|
||||
|
||||
// note is a number from 1-7 for A-G
|
||||
// acc is either "b", "n", or "#"
|
||||
// oct is 1-8 (or 9 for C)
|
||||
/datum/song/proc/playnote(note, acc as text, oct)
|
||||
// handle accidental -> B<>C of E<>F
|
||||
if(acc == "b" && (note == 3 || note == 6)) // C or F
|
||||
if(note == 3)
|
||||
oct--
|
||||
note--
|
||||
acc = "n"
|
||||
else if(acc == "#" && (note == 2 || note == 5)) // B or E
|
||||
if(note == 2)
|
||||
oct++
|
||||
note++
|
||||
acc = "n"
|
||||
else if(acc == "#" && (note == 7)) //G#
|
||||
note = 1
|
||||
acc = "b"
|
||||
else if(acc == "#") // mass convert all sharps to flats, octave jump already handled
|
||||
acc = "b"
|
||||
note++
|
||||
|
||||
// check octave, C is allowed to go to 9
|
||||
if(oct < 1 || (note == 3 ? oct > 9 : oct > 8))
|
||||
return
|
||||
|
||||
// now generate name
|
||||
var/soundfile = "sound/instruments/[instrumentDir]/[ascii2text(note+64)][acc][oct].[instrumentExt]"
|
||||
soundfile = file(soundfile)
|
||||
// make sure the note exists
|
||||
if(!fexists(soundfile))
|
||||
return
|
||||
// and play
|
||||
var/turf/source = get_turf(instrumentObj)
|
||||
var/sound/music_played = sound(soundfile)
|
||||
for(var/A in hearers(15, source))
|
||||
var/mob/M = A
|
||||
if(!M.client || !(M.client.prefs.sound & SOUND_INSTRUMENTS))
|
||||
continue
|
||||
M.playsound_local(source, null, 100, falloff = 5, S = music_played)
|
||||
|
||||
/datum/song/proc/shouldStopPlaying(mob/user)
|
||||
if(instrumentObj)
|
||||
//if(!user.canUseTopic(instrumentObj))
|
||||
//return 1
|
||||
return !instrumentObj.anchored // add special cases to stop in subclasses
|
||||
else
|
||||
return 1
|
||||
|
||||
/datum/song/proc/playsong(mob/user)
|
||||
while(repeat >= 0)
|
||||
var/cur_oct[7]
|
||||
var/cur_acc[7]
|
||||
for(var/i = 1 to 7)
|
||||
cur_oct[i] = 3
|
||||
cur_acc[i] = "n"
|
||||
|
||||
for(var/line in lines)
|
||||
for(var/beat in splittext(lowertext(line), ","))
|
||||
var/list/notes = splittext(beat, "/")
|
||||
for(var/note in splittext(notes[1], "-"))
|
||||
if(!playing || shouldStopPlaying(user)) //If the instrument is playing, or special case
|
||||
playing = 0
|
||||
return
|
||||
if(length(note) == 0)
|
||||
continue
|
||||
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)
|
||||
if(!text2num(ni))
|
||||
if(ni == "#" || ni == "b" || ni == "n")
|
||||
cur_acc[cur_note] = ni
|
||||
else if(ni == "s")
|
||||
cur_acc[cur_note] = "#" // so shift is never required
|
||||
else
|
||||
cur_oct[cur_note] = text2num(ni)
|
||||
playnote(cur_note, cur_acc[cur_note], cur_oct[cur_note])
|
||||
if(notes.len >= 2 && text2num(notes[2]))
|
||||
sleep(sanitize_tempo(tempo / text2num(notes[2])))
|
||||
else
|
||||
sleep(tempo)
|
||||
repeat--
|
||||
playing = 0
|
||||
repeat = 0
|
||||
|
||||
/datum/song/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if(!instrumentObj)
|
||||
return
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, instrumentObj, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, instrumentObj, ui_key, "song.tmpl", instrumentObj.name, 700, 500)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/datum/song/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
var/data[0]
|
||||
|
||||
data["lines"] = lines
|
||||
data["tempo"] = tempo
|
||||
|
||||
data["playing"] = playing
|
||||
data["help"] = help
|
||||
data["repeat"] = repeat
|
||||
data["maxRepeat"] = max_repeat
|
||||
data["minTempo"] = world.tick_lag
|
||||
data["maxTempo"] = 600
|
||||
|
||||
return data
|
||||
|
||||
/datum/song/Topic(href, href_list)
|
||||
if(!in_range(instrumentObj, usr) || (issilicon(usr) && instrumentObj.loc != usr) || !isliving(usr) || usr.incapacitated())
|
||||
usr << browse(null, "window=instrument")
|
||||
usr.unset_machine()
|
||||
return 1
|
||||
|
||||
instrumentObj.add_fingerprint(usr)
|
||||
|
||||
if(href_list["newsong"])
|
||||
playing = 0
|
||||
lines = new()
|
||||
tempo = sanitize_tempo(5) // default 120 BPM
|
||||
name = ""
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["import"])
|
||||
playing = 0
|
||||
var/t = ""
|
||||
do
|
||||
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message)
|
||||
if(!in_range(instrumentObj, usr))
|
||||
return
|
||||
|
||||
if(length(t) >= 12000)
|
||||
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
|
||||
if(cont == "no")
|
||||
break
|
||||
while(length(t) > 12000)
|
||||
|
||||
//split into lines
|
||||
spawn()
|
||||
lines = splittext(t, "\n")
|
||||
if(lines.len == 0)
|
||||
return 1
|
||||
if(copytext(lines[1],1,6) == "BPM: ")
|
||||
tempo = sanitize_tempo(600 / text2num(copytext(lines[1],6)))
|
||||
lines.Cut(1,2)
|
||||
else
|
||||
tempo = sanitize_tempo(5) // default 120 BPM
|
||||
if(lines.len > 200)
|
||||
to_chat(usr, "Too many lines!")
|
||||
lines.Cut(201)
|
||||
var/linenum = 1
|
||||
for(var/l in lines)
|
||||
if(length(l) > 200)
|
||||
to_chat(usr, "Line [linenum] too long!")
|
||||
lines.Remove(l)
|
||||
else
|
||||
linenum++
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["help"])
|
||||
help = !help
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops.
|
||||
if(playing)
|
||||
return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing.
|
||||
repeat += round(text2num(href_list["repeat"]))
|
||||
if(repeat < 0)
|
||||
repeat = 0
|
||||
if(repeat > max_repeat)
|
||||
repeat = max_repeat
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["tempo"])
|
||||
tempo = sanitize_tempo(tempo + text2num(href_list["tempo"]) * world.tick_lag)
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["play"])
|
||||
if(playing)
|
||||
return
|
||||
playing = 1
|
||||
spawn()
|
||||
playsong(usr)
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["insertline"])
|
||||
var/num = round(text2num(href_list["insertline"]))
|
||||
if(num < 1 || num > lines.len + 1)
|
||||
return
|
||||
|
||||
var/newline = html_encode(input("Enter your line: ", instrumentObj.name) as text|null)
|
||||
if(!newline || !in_range(instrumentObj, usr))
|
||||
return
|
||||
if(lines.len > 200)
|
||||
return
|
||||
if(length(newline) > 200)
|
||||
newline = copytext(newline, 1, 200)
|
||||
|
||||
lines.Insert(num, newline)
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["deleteline"])
|
||||
var/num = round(text2num(href_list["deleteline"]))
|
||||
if(num > lines.len || num < 1)
|
||||
return
|
||||
lines.Cut(num, num + 1)
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["modifyline"])
|
||||
var/num = round(text2num(href_list["modifyline"]))
|
||||
var/content = html_encode(input("Enter your line: ", instrumentObj.name, lines[num]) as text|null)
|
||||
if(!content || !in_range(instrumentObj, usr))
|
||||
return
|
||||
if(length(content) > 200)
|
||||
content = copytext(content, 1, 200)
|
||||
if(num > lines.len || num < 1)
|
||||
return
|
||||
lines[num] = content
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["stop"])
|
||||
playing = 0
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
/datum/song/proc/sanitize_tempo(new_tempo)
|
||||
new_tempo = abs(new_tempo)
|
||||
return max(round(new_tempo, world.tick_lag), world.tick_lag)
|
||||
|
||||
// subclass for handheld instruments, like violin
|
||||
/datum/song/handheld
|
||||
|
||||
/datum/song/handheld/shouldStopPlaying()
|
||||
if(instrumentObj)
|
||||
return !isliving(instrumentObj.loc)
|
||||
else
|
||||
return 1
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/obj/structure/piano
|
||||
name = "space minimoog"
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
icon_state = "minimoog"
|
||||
anchored = 1
|
||||
density = 1
|
||||
var/datum/song/song
|
||||
|
||||
|
||||
/obj/structure/piano/New()
|
||||
..()
|
||||
song = new("piano", src)
|
||||
|
||||
if(prob(50))
|
||||
name = "space minimoog"
|
||||
desc = "This is a minimoog, like a space piano, but more spacey!"
|
||||
icon_state = "minimoog"
|
||||
else
|
||||
name = "space piano"
|
||||
desc = "This is a space piano, like a regular piano, but always in tune! Even if the musician isn't."
|
||||
icon_state = "piano"
|
||||
|
||||
/obj/structure/piano/Destroy()
|
||||
QDEL_NULL(song)
|
||||
return ..()
|
||||
|
||||
/obj/structure/piano/Initialize()
|
||||
if(song)
|
||||
song.tempo = song.sanitize_tempo(song.tempo) // tick_lag isn't set when the map is loaded
|
||||
..()
|
||||
|
||||
/obj/structure/piano/attack_hand(mob/user as mob)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/structure/piano/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if(!isliving(user) || user.incapacitated() || !anchored)
|
||||
return
|
||||
|
||||
song.ui_interact(user, ui_key, ui, force_open)
|
||||
|
||||
/obj/structure/piano/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
return song.ui_data(user, ui_key, state)
|
||||
|
||||
/obj/structure/piano/Topic(href, href_list)
|
||||
song.Topic(href, href_list)
|
||||
|
||||
/obj/structure/piano/wrench_act(mob/user, obj/item/I)
|
||||
. = TRUE
|
||||
if(!I.tool_use_check(user, 0))
|
||||
return
|
||||
if(!anchored && !isinspace())
|
||||
WRENCH_ANCHOR_MESSAGE
|
||||
if(!I.use_tool(src, user, 20, volume = I.tool_volume))
|
||||
return
|
||||
user.visible_message( \
|
||||
"[user] tightens [src]'s casters.", \
|
||||
"<span class='notice'> You have tightened [src]'s casters. Now it can be played again.</span>", \
|
||||
"You hear ratchet.")
|
||||
anchored = TRUE
|
||||
else if(anchored)
|
||||
to_chat(user, "<span class='notice'> You begin to loosen [src]'s casters...</span>")
|
||||
if(!I.use_tool(src, user, 40, volume = I.tool_volume))
|
||||
return
|
||||
user.visible_message( \
|
||||
"[user] loosens [src]'s casters.", \
|
||||
"<span class='notice'> You have loosened [src]. Now it can be pulled somewhere else.</span>", \
|
||||
"You hear ratchet.")
|
||||
anchored = FALSE
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[src] needs to be bolted to the floor!</span>")
|
||||
@@ -292,12 +292,12 @@
|
||||
|
||||
/obj/structure/sign/directions/engineering
|
||||
name = "\improper Engineering Department"
|
||||
desc = "A direction sign, pointing out which way the Engineering department is."
|
||||
desc = "A direction sign, pointing out which way the Engineering Department is."
|
||||
icon_state = "direction_eng"
|
||||
|
||||
/obj/structure/sign/directions/security
|
||||
name = "\improper Security Department"
|
||||
desc = "A direction sign, pointing out which way the Security department is."
|
||||
desc = "A direction sign, pointing out which way the Security Department is."
|
||||
icon_state = "direction_sec"
|
||||
|
||||
/obj/structure/sign/directions/medical
|
||||
@@ -307,12 +307,12 @@
|
||||
|
||||
/obj/structure/sign/directions/evac
|
||||
name = "\improper Escape Arm"
|
||||
desc = "A direction sign, pointing out which way escape shuttle dock is."
|
||||
desc = "A direction sign, pointing out which way Escape Shuttle Dock is."
|
||||
icon_state = "direction_evac"
|
||||
|
||||
/obj/structure/sign/directions/cargo
|
||||
name = "\improper Cargo Department"
|
||||
desc = "A direction sign, pointing out which way the Cargo department is."
|
||||
desc = "A direction sign, pointing out which way the Cargo Department is."
|
||||
icon_state = "direction_supply"
|
||||
|
||||
/obj/structure/sign/explosives
|
||||
|
||||
Reference in New Issue
Block a user