diff --git a/baystation12.dme b/baystation12.dme
index 3abe6716eeb..9032f3da7e1 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -262,6 +262,7 @@
#define FILE_DIR "sound/misc"
#define FILE_DIR "sound/music"
#define FILE_DIR "sound/piano"
+#define FILE_DIR "sound/violin"
#define FILE_DIR "sound/voice"
#define FILE_DIR "sound/weapons"
#define FILE_DIR "tools"
@@ -675,6 +676,7 @@
#include "code\game\objects\items\devices\traitordevices.dm"
#include "code\game\objects\items\devices\transfer_valve.dm"
#include "code\game\objects\items\devices\uplinks.dm"
+#include "code\game\objects\items\devices\violin.dm"
#include "code\game\objects\items\devices\PDA\cart.dm"
#include "code\game\objects\items\devices\PDA\chatroom.dm"
#include "code\game\objects\items\devices\PDA\PDA.dm"
@@ -705,6 +707,7 @@
#include "code\game\objects\items\weapons\cards_ids.dm"
#include "code\game\objects\items\weapons\cigs_lighters.dm"
#include "code\game\objects\items\weapons\clown_items.dm"
+#include "code\game\objects\items\weapons\cosmetics.dm"
#include "code\game\objects\items\weapons\dice.dm"
#include "code\game\objects\items\weapons\dna_injector.dm"
#include "code\game\objects\items\weapons\explosives.dm"
@@ -851,6 +854,7 @@
#include "code\modules\admin\create_mob.dm"
#include "code\modules\admin\create_object.dm"
#include "code\modules\admin\create_turf.dm"
+#include "code\modules\admin\holder2.dm"
#include "code\modules\admin\IsBanned.dm"
#include "code\modules\admin\NewBan.dm"
#include "code\modules\admin\newbanjob.dm"
@@ -993,7 +997,6 @@
#include "code\modules\mob\update_icons.dm"
#include "code\modules\mob\dead\death.dm"
#include "code\modules\mob\dead\observer\hud.dm"
-#include "code\modules\mob\dead\observer\login.dm"
#include "code\modules\mob\dead\observer\logout.dm"
#include "code\modules\mob\dead\observer\observer.dm"
#include "code\modules\mob\dead\observer\say.dm"
diff --git a/code/FEA/FEA_gas_mixture.dm b/code/FEA/FEA_gas_mixture.dm
index ee7592b975f..9d609e673e7 100644
--- a/code/FEA/FEA_gas_mixture.dm
+++ b/code/FEA/FEA_gas_mixture.dm
@@ -546,12 +546,6 @@ What are the archived variables for?
var/old_self_heat_capacity = 0
var/old_sharer_heat_capacity = 0
-
- //These two variables have been commented out. The author did not leave documentation on what they were supposed to be for. -Rockdtben
- //These two variables are only changed and do not exist outside of this proc. -Rockdtben
- //var/heat_self_to_sharer = 0
- //var/heat_sharer_to_self = 0
-
var/heat_capacity_self_to_sharer = 0
var/heat_capacity_sharer_to_self = 0
@@ -561,28 +555,22 @@ What are the archived variables for?
if(delta_air)
var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air
if(delta_air > 0)
- //heat_self_to_sharer += air_heat_capacity*temperature_archived
heat_capacity_self_to_sharer += air_heat_capacity
else
- //heat_sharer_to_self -= air_heat_capacity*sharer.temperature_archived
heat_capacity_sharer_to_self -= air_heat_capacity
if(delta_carbon_dioxide)
var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide
if(delta_carbon_dioxide > 0)
- //heat_self_to_sharer += carbon_dioxide_heat_capacity*temperature_archived
heat_capacity_self_to_sharer += carbon_dioxide_heat_capacity
else
- //heat_sharer_to_self -= carbon_dioxide_heat_capacity*sharer.temperature_archived
heat_capacity_sharer_to_self -= carbon_dioxide_heat_capacity
if(delta_toxins)
var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins
if(delta_toxins > 0)
- //heat_self_to_sharer += toxins_heat_capacity*temperature_archived
heat_capacity_self_to_sharer += toxins_heat_capacity
else
- //heat_sharer_to_self -= toxins_heat_capacity*sharer.temperature_archived
heat_capacity_sharer_to_self -= toxins_heat_capacity
old_self_heat_capacity = heat_capacity()*group_multiplier
@@ -624,10 +612,8 @@ What are the archived variables for?
if(delta)
var/individual_heat_capacity = trace_gas.specific_heat*delta
if(delta > 0)
- //heat_self_to_sharer += individual_heat_capacity*temperature_archived
heat_capacity_self_to_sharer += individual_heat_capacity
else
- //heat_sharer_to_self -= individual_heat_capacity*sharer.temperature_archived
heat_capacity_sharer_to_self -= individual_heat_capacity
moved_moles += delta
@@ -652,7 +638,6 @@ What are the archived variables for?
//Guaranteed transfer from sharer to self
var/individual_heat_capacity = trace_gas.specific_heat*delta
- //heat_sharer_to_self += individual_heat_capacity*sharer.temperature_archived
heat_capacity_sharer_to_self += individual_heat_capacity
moved_moles += -delta
diff --git a/code/FEA/FEA_system.dm b/code/FEA/FEA_system.dm
index 963b9662179..7d7d9754602 100644
--- a/code/FEA/FEA_system.dm
+++ b/code/FEA/FEA_system.dm
@@ -277,8 +277,7 @@ datum
return 1
process_update_tiles()
- for(var/turf in tiles_to_update)
- var/turf/simulated/T = turf
+ for(var/turf/simulated/T in tiles_to_update)
T.update_air_properties()
/*
for(var/obj/movable/floor/O in tiles_to_update)
diff --git a/code/controllers/_DynamicAreaLighting_TG.dm b/code/controllers/_DynamicAreaLighting_TG.dm
index df8e2ecbd2f..2bc317aabbc 100644
--- a/code/controllers/_DynamicAreaLighting_TG.dm
+++ b/code/controllers/_DynamicAreaLighting_TG.dm
@@ -1,7 +1,7 @@
/*
Modified DynamicAreaLighting for TGstation - Coded by Carnwennan
- This is TG's 'new' lighting system. It's basically a heavily modified mix of combination of Forum_Account's and
+ This is TG's 'new' lighting system. It's basically a heavily modified combination of Forum_Account's and
ShadowDarke's respective lighting libraries. Credits, where due, to them.
Like sd_DAL (what we used to use), it changes the shading overlays of areas by splitting each type of area into sub-areas
@@ -29,7 +29,6 @@
mob luminosity will be lower than expected when one of multiple light sources is dropped after exceeding the maximum luminosity
Shuttles still do not have support for dynamic lighting (I hope to fix this at some point)
No directional lighting support. Fairly easy to add this and the code is ready.
- When opening airlocks etc, lighting does not always update to account for the change in opacity.
*/
#define LIGHTING_MAX_LUMINOSITY 12 //Hard maximum luminosity to prevet lag which could be caused by coders making mini-suns
@@ -272,13 +271,13 @@ area
proc/SetLightLevel(light)
if(!src) return
- if(light < 0)
+ if(light <= 0)
light = 0
-// luminosity = 0
+ luminosity = 0
else
if(light > lighting_controller.lighting_states)
light = lighting_controller.lighting_states
-// luminosity = 1
+ luminosity = 1
if(lighting_overlay)
overlays -= lighting_overlay
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index ba57420f2b7..1f99541544c 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -50,6 +50,7 @@
var/kick_inactive = 0 //force disconnect for inactive players
var/load_jobs_from_txt = 0
var/ToRban = 0
+ var/automute_on = 0 //enables automuting/spam prevention
var/usealienwhitelist = 0
@@ -342,10 +343,7 @@
if("tor_ban")
ToRban = 1
- if("usealienwhitelist")
- usealienwhitelist = 1
-
- else
+ if("automute_on") automute_on = 1 if("usealienwhitelist") usealienwhitelist = 1 else
diary << "Unknown setting in configuration: '[name]'"
else if(type == "game_options")
diff --git a/code/controllers/voting.dm b/code/controllers/voting.dm
index bb1219d784e..f2596cd5f20 100644
--- a/code/controllers/voting.dm
+++ b/code/controllers/voting.dm
@@ -53,10 +53,25 @@ datum/controller/vote
proc/get_result()
//get the highest number of votes
var/greatest_votes = 0
+ var/total_votes = 0
for(var/option in choices)
var/votes = choices[option]
+ total_votes += votes
if(votes > greatest_votes)
greatest_votes = votes
+ //default-vote for everyone who didn't vote
+ if(!config.vote_no_default && choices.len)
+ var/non_voters = (client_list.len - total_votes)
+ if(non_voters > 0)
+ if(mode == "restart")
+ choices["Continue Playing"] += non_voters
+ if(choices["Continue Playing"] >= greatest_votes)
+ greatest_votes = choices["Continue Playing"]
+ else if(mode == "gamemode")
+ if(master_mode in choices)
+ choices[master_mode] += non_voters
+ if(choices[master_mode] >= greatest_votes)
+ greatest_votes = choices[master_mode]
//get all options with that many votes and return them in a list
. = list()
if(greatest_votes)
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 43ea51c2171..7f58a1742db 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -487,6 +487,7 @@ datum/mind
current << "\red You have been brainwashed! You are no longer a head revolutionary!"
ticker.mode.update_rev_icons_removed(src)
special_role = null
+ log_admin("[key_name_admin(usr)] has de-rev'ed [current].")
if("rev")
if(src in ticker.mode.head_revolutionaries)
@@ -500,6 +501,7 @@ datum/mind
ticker.mode.revolutionaries += src
ticker.mode.update_rev_icons_added(src)
special_role = "Revolutionary"
+ log_admin("[key_name(usr)] has rev'ed [current].")
if("headrev")
if(src in ticker.mode.revolutionaries)
@@ -524,6 +526,7 @@ datum/mind
ticker.mode.head_revolutionaries += src
ticker.mode.update_rev_icons_added(src)
special_role = "Head Revolutionary"
+ log_admin("[key_name_admin(usr)] has head-rev'ed [current].")
if("autoobjectives")
ticker.mode.forge_revolutionary_objectives(src)
@@ -572,6 +575,7 @@ datum/mind
cult.memoize_cult_objectives(src)
current << "\red You have been brainwashed! You are no longer a cultist!"
memory = ""
+ log_admin("[key_name_admin(usr)] has de-cult'ed [current].")
if("cultist")
if(!(src in ticker.mode.cult))
ticker.mode.cult += src
@@ -582,6 +586,7 @@ datum/mind
var/datum/game_mode/cult/cult = ticker.mode
if (istype(cult))
cult.memoize_cult_objectives(src)
+ log_admin("[key_name_admin(usr)] has cult'ed [current].")
if("tome")
var/mob/living/carbon/human/H = current
if (istype(H))
@@ -612,12 +617,14 @@ datum/mind
special_role = null
current.spellremove(current, config.feature_object_spell_system? "object":"verb")
current << "\red You have been brainwashed! You are no longer a wizard!"
+ log_admin("[key_name_admin(usr)] has de-wizard'ed [current].")
if("wizard")
if(!(src in ticker.mode.wizards))
ticker.mode.wizards += src
special_role = "Wizard"
//ticker.mode.learn_basic_spells(current)
current << "\red You are the Space Wizard!"
+ log_admin("[key_name_admin(usr)] has wizard'ed [current].")
if("lair")
current.loc = pick(wizardstart)
if("dressup")
@@ -637,12 +644,14 @@ datum/mind
current.remove_changeling_powers()
if(changeling) del(changeling)
current << "You grow weak and lose your powers! You are no longer a changeling and are stuck in your current form!"
+ log_admin("[key_name_admin(usr)] has de-changeling'ed [current].")
if("changeling")
if(!(src in ticker.mode.changelings))
ticker.mode.changelings += src
ticker.mode.grant_changeling_powers(current)
special_role = "Changeling"
current << "Your powers are awoken. A flash of memory returns to us...we are a changeling!"
+ log_admin("[key_name_admin(usr)] has changeling'ed [current].")
if("autoobjectives")
ticker.mode.forge_changeling_objectives(src)
usr << "\blue The objectives for changeling [key] have been generated. You can edit them and anounce manually."
@@ -666,6 +675,7 @@ datum/mind
for (var/datum/objective/nuclear/O in objectives)
objectives-=O
current << "\red You have been brainwashed! You are no longer a syndicate operative!"
+ log_admin("[key_name_admin(usr)] has de-nuke op'ed [current].")
if("nuclear")
if(!(src in ticker.mode.syndicates))
ticker.mode.syndicates += src
@@ -678,6 +688,7 @@ datum/mind
current << "\blue You are a [syndicate_name()] agent!"
ticker.mode.forge_syndicate_objectives(src)
ticker.mode.greet_syndicate(src)
+ log_admin("[key_name_admin(usr)] has nuke op'ed [current].")
if("lair")
current.loc = get_turf(locate("landmark*Syndicate-Spawn"))
if("dressup")
@@ -713,12 +724,14 @@ datum/mind
ticker.mode.traitors -= src
special_role = null
current << "\red You have been brainwashed! You are no longer a traitor!"
+ log_admin("[key_name_admin(usr)] has de-traitor'ed [current].")
if("traitor")
if(!(src in ticker.mode.traitors))
ticker.mode.traitors += src
special_role = "traitor"
current << "\red You are a traitor!"
+ log_admin("[key_name_admin(usr)] has traitor'ed [current].")
if("autoobjectives")
ticker.mode.forge_traitor_objectives(src)
@@ -798,9 +811,11 @@ datum/mind
current.icon_state = "ai"
current << "\red You have been patched! You are no longer malfunctioning!"
+ log_admin("[key_name_admin(usr)] has de-malf'ed [current].")
if("malf")
make_AI_Malf()
+ log_admin("[key_name_admin(usr)] has malf'ed [current].")
if("unemag")
var/mob/living/silicon/robot/R = current
@@ -817,6 +832,7 @@ datum/mind
else if(R.module_state_3 == R.module.emag)
R.module_state_3 = null
R.contents -= R.module.emag
+ log_admin("[key_name_admin(usr)] has unemag'ed [R].")
if("unemagcyborgs")
if (istype(current, /mob/living/silicon/ai))
@@ -835,6 +851,7 @@ datum/mind
else if(R.module_state_3 == R.module.emag)
R.module_state_3 = null
R.contents -= R.module.emag
+ log_admin("[key_name_admin(usr)] has unemag'ed [ai]'s Cyborgs.")
else if (href_list["common"])
switch(href_list["common"])
diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm
index 7663f059914..419169c29e7 100755
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -599,7 +599,8 @@
/datum/supply_packs/randomised/contraband
num_contained = 5
contains = list(/obj/item/weapon/contraband/poster,
- /obj/item/weapon/cigpacket/dromedaryco)
+ /obj/item/weapon/cigpacket/dromedaryco,
+ /obj/item/weapon/lipstick/random)
name = "Contraband crate"
cost = 30
containertype = /obj/structure/closet/crate
diff --git a/code/defines/obj.dm b/code/defines/obj.dm
index 56c16c2e748..4915a0d1dee 100644
--- a/code/defines/obj.dm
+++ b/code/defines/obj.dm
@@ -25,22 +25,6 @@
mouse_opacity = 0
unacidable = 1//Just to be sure.
-/obj/admins
- name = "admins"
- var/rank = null
- var/owner = null
- var/state = 1
- //state = 1 for playing : default
- //state = 2 for observing
- var/admincaster_screen = 0 //See newscaster.dm under machinery for a full description
- var/datum/feed_message/admincaster_feed_message = new /datum/feed_message //These two will act as holders.
- var/datum/feed_channel/admincaster_feed_channel = new /datum/feed_channel
- var/admincaster_signature //What you'll sign the newsfeeds as
-
-/obj/admins/New()
- src.admincaster_signature = "Nanotrasen Officer #[rand(0,9)][rand(0,9)][rand(0,9)]"
- ..()
-
/obj/effect/beam
name = "beam"
unacidable = 1//Just to be sure.
diff --git a/code/defines/procs/helpers.dm b/code/defines/procs/helpers.dm
index 3af4af61ded..787bfe1356c 100644
--- a/code/defines/procs/helpers.dm
+++ b/code/defines/procs/helpers.dm
@@ -544,7 +544,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
else
linked = 0
- if (the_client && the_client.holder && the_client.stealth && !include_name)
+ if (the_client && the_client.holder && the_client.holder.fakekey && !include_name)
text += "Administrator"
else
text += "[the_key]"
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index d24ad0796c5..1dbda6bdcdf 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -1091,7 +1091,7 @@ var/using_new_click_proc = 0 //TODO ERRORAGE (This is temporary, while the DblCl
See the previous More info, for... more info...
*/
- if (!( ok ))
+ //del(D) // Garbage Collect Dummy D.loc = null D = null // ------- DUMMY OBJECT'S SERVED IT'S PURPOSE, IT'S REWARDED WITH A SWIFT DELETE ------- if (!( ok ))
// ------- TESTS ABOVE DETERMINED YOU CANNOT REACH THE TILE -------
return 0
@@ -1355,4 +1355,4 @@ var/list/DummyCache = list()
return 0
/atom/proc/checkpass(passflag)
- return pass_flags&passflag
+ return pass_flags&passflag/*/client/verb/check_dummy() set name = "List Dummies" set category = "Debug" var/list/dummies = list() for(var/obj/item/weapon/dummy/D in world) usr << "[D] - [D.x], [D.y], [D.z] - [D.loc]" dummies += D usr << "[dummies.len] found!"*/
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm
index 54824cbaf1b..cf045d0464a 100644
--- a/code/game/gamemodes/changeling/changeling_powers.dm
+++ b/code/game/gamemodes/changeling/changeling_powers.dm
@@ -12,6 +12,16 @@
if(!(P in src.verbs))
src.verbs += P.verbpath
+ if(!powerinstances.len)
+ for(var/P in powers)
+ powerinstances += new P()
+
+ // Code to auto-purchase free powers.
+ for(var/datum/power/changeling/P in powerinstances)
+ if(!P.genomecost) // Is it free?
+ if(!(P in mind.changeling.purchasedpowers)) // Do we not have it already?
+ mind.changeling.purchasePower(P.name)// Purchase it.
+
mind.changeling.absorbed_dna |= dna
return 1
@@ -25,29 +35,29 @@
//Helper proc. Does all the checks and stuff for us to avoid copypasta
/mob/proc/changeling_power(var/required_chems=0, var/required_dna=0, var/max_genetic_damage=100, var/max_stat=0)
- if(!usr) return
- if(!usr.mind) return
- if(!iscarbon(usr)) return
+ if(!src) return
+ if(!src.mind) return
+ if(!iscarbon(src)) return
- var/datum/changeling/changeling = usr.mind.changeling
+ var/datum/changeling/changeling = src.mind.changeling
if(!changeling)
world.log << "[src] has the changeling_transform() verb but is not a changeling."
return
if(usr.stat > max_stat)
- usr << "We are incapacitated."
+ src << "We are incapacitated."
return
if(changeling.absorbed_dna.len < required_dna)
- usr << "We require at least [required_dna] samples of compatible DNA."
+ src << "We require at least [required_dna] samples of compatible DNA."
return
if(changeling.chem_charges < required_chems)
- usr << "We require at least [required_chems] units of chemicals to do that!"
+ src << "We require at least [required_chems] units of chemicals to do that!"
return
if(changeling.geneticdamage > max_genetic_damage)
- usr << usr << "Our geneomes are still reassembling. We need time to recover first."
+ src << "Our geneomes are still reassembling. We need time to recover first."
return
return changeling
@@ -586,7 +596,7 @@
var/mob/living/carbon/T = changeling_sting(30,/mob/proc/changeling_paralysis_sting)
if(!T) return 0
T << "Your muscles begin to painfully tighten."
- T.Weaken(10)
+ T.Weaken(20)
feedback_add_details("changeling_powers","PS")
return 1
diff --git a/code/game/gamemodes/changeling/modularchangling.dm b/code/game/gamemodes/changeling/modularchangling.dm
index 69fc5c90030..32c999f0b98 100644
--- a/code/game/gamemodes/changeling/modularchangling.dm
+++ b/code/game/gamemodes/changeling/modularchangling.dm
@@ -424,18 +424,21 @@ var/list/datum/power/changeling/powerinstances = list()
-/datum/changeling/proc/purchasePower(var/datum/power/changeling/Pname)
+/datum/changeling/proc/purchasePower(var/Pname)
if(!usr.mind || !usr.mind.changeling)
return
// src = usr.mind.changeling
- var/datum/power/changeling/Thepower = null
+ var/datum/power/changeling/Thepower = Pname
+
for (var/datum/power/changeling/P in powerinstances)
+ //world << "[P] - [Pname] = [P.name == Pname ? "True" : "False"]"
if(P.name == Pname)
Thepower = P
break
+
if(Thepower == null)
usr << "This is awkward. Changeling power purchase failed, please report this bug to a coder!"
return
diff --git a/code/game/gamemodes/factions.dm b/code/game/gamemodes/factions.dm
index e137c2e105f..cd7ae219ab3 100644
--- a/code/game/gamemodes/factions.dm
+++ b/code/game/gamemodes/factions.dm
@@ -134,7 +134,7 @@ Whitespace:Seperator;
Stealth and Camouflage Items;
/obj/item/clothing/under/chameleon:3:Chameleon Jumpsuit;
/obj/item/clothing/shoes/syndigaloshes:2:No-Slip Syndicate Shoes;
-/obj/item/weapon/card/id/syndicate:3:Agent ID card;
+/obj/item/weapon/card/id/syndicate:2:Agent ID card;
/obj/item/clothing/mask/gas/voice:4:Voice Changer;
/obj/item/device/chameleon:4:Chameleon-Projector;
Whitespace:Seperator;
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index afbf6da52ba..5240f2b3674 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -44,7 +44,7 @@ Whitespace:Seperator;
Stealth and Camouflage Items;
/obj/item/clothing/under/chameleon:3:Chameleon Jumpsuit;
/obj/item/clothing/shoes/syndigaloshes:2:No-Slip Syndicate Shoes;
-/obj/item/weapon/card/id/syndicate:3:Agent ID card;
+/obj/item/weapon/card/id/syndicate:2:Agent ID card;
/obj/item/clothing/mask/gas/voice:4:Voice Changer;
/obj/item/device/chameleon:4:Chameleon-Projector;
Whitespace:Seperator;
diff --git a/code/game/machinery/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm
index 76c0ca083f8..b923672bc13 100644
--- a/code/game/machinery/pipe/pipe_dispenser.dm
+++ b/code/game/machinery/pipe/pipe_dispenser.dm
@@ -138,14 +138,17 @@ Nah
return
var/dat = {"Disposal Pipes
-Pipe
-Bent Pipe
-Junction
-Y-Junction
-Trunk
-Bin
-Outlet
-Chute
+Pipe
+Bent Pipe
+
+Junction
+Y-Junction
+Sorting Junction
+
+Trunk
+Bin
+Outlet
+Chute
"}
user << browse("
[src][dat]", "window=pipedispenser")
@@ -159,33 +162,20 @@ Nah
return
usr.machine = src
src.add_fingerprint(usr)
- if(href_list["dmake"])
+ if(href_list["ptype"])
if(unwrenched || !usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
usr << browse(null, "window=pipedispenser")
return
if(!wait)
- var/p_type = text2num(href_list["dmake"])
var/obj/structure/disposalconstruct/C = new (src.loc)
- switch(p_type)
- if(0)
- C.ptype = 0
- if(1)
- C.ptype = 1
- if(2)
- C.ptype = 2
- if(3)
- C.ptype = 4
- if(4)
- C.ptype = 5
- if(5)
- C.ptype = 6
- C.density = 1
- if(6)
- C.ptype = 7
- C.density = 1
- if(7)
- C.ptype = 8
- C.density = 1
+
+ var/p_type = text2num(href_list["ptype"])
+ C.ptype = p_type
+
+ if(href_list["density"])
+ var/p_density = text2num(href_list["density"])
+ C.density = p_density
+
C.add_fingerprint(usr)
C.update()
wait = 1
diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm
index 00e94244285..eb3e723a232 100644
--- a/code/game/objects/items/devices/PDA/cart.dm
+++ b/code/game/objects/items/devices/PDA/cart.dm
@@ -282,7 +282,6 @@ Code:
if (43) //Muskets' and Rockdtben's power monitor :D
menu = "
Power Monitors - Please select one
"
powmonitor = null
- powermonitors = null
powermonitors = list()
var/powercount = 0
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index 89f98691793..043e89201da 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -47,7 +47,7 @@
A.loc = src
user << "You attach the [item] to the valve controls and secure it."
A.holder = src
- A.toggle_secure()
+ A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb).
bombers += "[key_name(user)] attached a [item] to a transfer valve."
message_admins("[key_name_admin(user)] attached a [item] to a transfer valve.")
diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm
index e23b308fe05..6c9f58a5885 100644
--- a/code/game/objects/items/devices/uplinks.dm
+++ b/code/game/objects/items/devices/uplinks.dm
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
//This could either be split into the proper DM files or placed somewhere else all together, but it'll do for now -Nodrak
/*
@@ -373,3 +374,380 @@ A list of items and costs is stored under the datum of every game mode, alongsid
+=======
+//This could either be split into the proper DM files or placed somewhere else all together, but it'll do for now -Nodrak
+
+/*
+
+A list of items and costs is stored under the datum of every game mode, alongside the number of crystals, and the welcoming message.
+
+*/
+
+/obj/item/device/uplink
+ var/welcome // Welcoming menu message
+ var/items // List of items
+ var/item_data // raw item text
+ var/list/ItemList // Parsed list of items
+ var/uses // Numbers of crystals
+ // List of items not to shove in their hands.
+ var/list/NotInHand = list(/obj/machinery/singularity_beacon/syndicate)
+
+/obj/item/device/uplink/New()
+ welcome = ticker.mode.uplink_welcome
+ if(!item_data)
+ items = dd_replacetext(ticker.mode.uplink_items, "\n", "") // Getting the text string of items
+ else
+ items = dd_replacetext(item_data)
+ ItemList = dd_text2list(src.items, ";") // Parsing the items text string
+ uses = ticker.mode.uplink_uses
+
+//Let's build a menu!
+/obj/item/device/uplink/proc/generate_menu()
+
+ var/dat = "[src.welcome]
"
+ dat += "Tele-Crystals left: [src.uses]
"
+ dat += "
"
+ dat += "Request item:
"
+ dat += "Each item costs a number of tele-crystals as indicated by the number following their name.
"
+
+ var/cost
+ var/item
+ var/name
+ var/path_obj
+ var/path_text
+ var/category_items = 1 //To prevent stupid :P
+
+ for(var/D in ItemList)
+ var/list/O = stringsplit(D, ":")
+ if(O.len != 3) //If it is not an actual item, make a break in the menu.
+ if(O.len == 1) //If there is one item, it's probably a title
+ dat += "[O[1]]
"
+ category_items = 0
+ else //Else, it's a white space.
+ if(category_items < 1) //If there were no itens in the last category...
+ dat += "We apologize, as you could not afford anything from this category.
"
+ dat += "
"
+ continue
+
+ path_text = O[1]
+ cost = text2num(O[2])
+
+ if(cost>uses)
+ continue
+
+ path_obj = text2path(path_text)
+ item = new path_obj()
+ name = O[3]
+ del item
+
+ dat += "[name] ([cost])
"
+ category_items++
+
+ dat += "Random Item (??)
"
+ dat += "
"
+ return dat
+
+//If 'random' was selected
+/obj/item/device/uplink/proc/chooseRandomItem()
+ var/list/randomItems = list()
+
+ //Sorry for all the ifs, but it makes it 1000 times easier for other people/servers to add or remove items from this list
+ //Add only items the player can afford:
+ if(uses > 19)
+ randomItems.Add("/obj/item/weapon/circuitboard/teleporter") //Teleporter Circuit Board (costs 20, for nuke ops)
+
+ if(uses > 9)
+ randomItems.Add("/obj/item/toy/syndicateballoon")//Syndicate Balloon
+ randomItems.Add("/obj/item/weapon/storage/syndie_kit/imp_uplink") //Uplink Implanter
+ randomItems.Add("/obj/item/weapon/storage/box/syndicate") //Syndicate bundle
+
+ //if(uses > 8) //Nothing... yet.
+ //if(uses > 7) //Nothing... yet.
+
+ if(uses > 6)
+ randomItems.Add("/obj/item/weapon/aiModule/syndicate") //Hacked AI Upload Module
+ randomItems.Add("/obj/item/device/radio/beacon/syndicate") //Singularity Beacon
+
+ if(uses > 5)
+ randomItems.Add("/obj/item/weapon/gun/projectile") //Revolver
+
+ if(uses > 4)
+ randomItems.Add("/obj/item/weapon/gun/energy/crossbow") //Energy Crossbow
+ randomItems.Add("/obj/item/device/powersink") //Powersink
+
+ if(uses > 3)
+ randomItems.Add("/obj/item/weapon/melee/energy/sword") //Energy Sword
+ randomItems.Add("/obj/item/clothing/mask/gas/voice") //Voice Changer
+ randomItems.Add("/obj/item/device/chameleon") //Chameleon Projector
+
+ if(uses > 2)
+ randomItems.Add("/obj/item/weapon/storage/emp_kit") //EMP Grenades
+ randomItems.Add("/obj/item/weapon/pen/paralysis") //Paralysis Pen
+ randomItems.Add("/obj/item/weapon/cartridge/syndicate") //Detomatix Cartridge
+ randomItems.Add("/obj/item/clothing/under/chameleon") //Chameleon Jumpsuit
+ randomItems.Add("/obj/item/weapon/card/id/syndicate") //Agent ID Card
+ randomItems.Add("/obj/item/weapon/card/emag") //Cryptographic Sequencer
+ randomItems.Add("/obj/item/weapon/storage/syndie_kit/space") //Syndicate Space Suit
+ randomItems.Add("/obj/item/device/encryptionkey/binary") //Binary Translator Key
+ randomItems.Add("/obj/item/weapon/storage/syndie_kit/imp_freedom") //Freedom Implant
+ randomItems.Add("/obj/item/clothing/glasses/thermal/syndi") //Thermal Imaging Goggles
+
+ if(uses > 1)
+/*
+ var/list/usrItems = usr.get_contents() //Checks to see if the user has a revolver before giving ammo
+ var/hasRevolver = 0
+ for(var/obj/I in usrItems) //Only add revolver ammo if the user has a gun that can shoot it
+ if(istype(I,/obj/item/weapon/gun/projectile))
+ hasRevolver = 1
+
+ if(hasRevolver) randomItems.Add("/obj/item/ammo_magazine/a357") //Revolver ammo
+*/
+ randomItems.Add("/obj/item/ammo_magazine/a357") //Revolver ammo
+ randomItems.Add("/obj/item/clothing/shoes/syndigaloshes") //No-Slip Syndicate Shoes
+ randomItems.Add("/obj/item/weapon/plastique") //C4
+
+ if(uses > 0)
+ randomItems.Add("/obj/item/weapon/soap/syndie") //Syndicate Soap
+ randomItems.Add("/obj/item/weapon/storage/toolbox/syndicate") //Syndicate Toolbox
+
+ if(!randomItems.len)
+ del(randomItems)
+ return 0
+ else
+ var/buyItem = pick(randomItems)
+
+ switch(buyItem) //Ok, this gets a little messy, sorry.
+ if("/obj/item/weapon/circuitboard/teleporter")
+ uses -= 20
+ if("/obj/item/toy/syndicateballoon" , "/obj/item/weapon/storage/syndie_kit/imp_uplink" , "/obj/item/weapon/storage/box/syndicate")
+ uses -= 10
+ if("/obj/item/weapon/aiModule/syndicate" , "/obj/item/device/radio/beacon/syndicate")
+ uses -= 7
+ if("/obj/item/weapon/gun/projectile")
+ uses -= 6
+ if("/obj/item/weapon/gun/energy/crossbow" , "/obj/item/device/powersink")
+ uses -= 5
+ if("/obj/item/weapon/melee/energy/sword" , "/obj/item/clothing/mask/gas/voice" , "/obj/item/device/chameleon")
+ uses -= 4
+ if("/obj/item/weapon/storage/emp_kit" , "/obj/item/weapon/pen/paralysis" , "/obj/item/weapon/cartridge/syndicate" , "/obj/item/clothing/under/chameleon" , \
+ "/obj/item/weapon/card/emag" , "/obj/item/weapon/storage/syndie_kit/space" , "/obj/item/device/encryptionkey/binary" , \
+ "/obj/item/weapon/storage/syndie_kit/imp_freedom" , "/obj/item/clothing/glasses/thermal/syndi")
+ uses -= 3
+ if("/obj/item/ammo_magazine/a357" , "/obj/item/clothing/shoes/syndigaloshes" , "/obj/item/weapon/plastique", "/obj/item/weapon/card/id/syndicate")
+ uses -= 2
+ if("/obj/item/weapon/soap/syndie" , "/obj/item/weapon/storage/toolbox/syndicate")
+ uses -= 1
+ del(randomItems)
+ return buyItem
+
+/obj/item/device/uplink/proc/handleStatTracking(var/boughtItem)
+//For stat tracking, sorry for making it so ugly
+ if(!boughtItem) return
+
+ switch(boughtItem)
+ if("/obj/item/weapon/circuitboard/teleporter")
+ feedback_add_details("traitor_uplink_items_bought","TP")
+ if("/obj/item/toy/syndicateballoon")
+ feedback_add_details("traitor_uplink_items_bought","BS")
+ if("/obj/item/weapon/storage/syndie_kit/imp_uplink")
+ feedback_add_details("traitor_uplink_items_bought","UI")
+ if("/obj/item/weapon/storage/box/syndicate")
+ feedback_add_details("traitor_uplink_items_bought","BU")
+ if("/obj/item/weapon/aiModule/syndicate")
+ feedback_add_details("traitor_uplink_items_bought","AI")
+ if("/obj/item/device/radio/beacon/syndicate")
+ feedback_add_details("traitor_uplink_items_bought","SB")
+ if("/obj/item/weapon/gun/projectile")
+ feedback_add_details("traitor_uplink_items_bought","RE")
+ if("/obj/item/weapon/gun/energy/crossbow")
+ feedback_add_details("traitor_uplink_items_bought","XB")
+ if("/obj/item/device/powersink")
+ feedback_add_details("traitor_uplink_items_bought","PS")
+ if("/obj/item/weapon/melee/energy/sword")
+ feedback_add_details("traitor_uplink_items_bought","ES")
+ if("/obj/item/clothing/mask/gas/voice")
+ feedback_add_details("traitor_uplink_items_bought","VC")
+ if("/obj/item/device/chameleon")
+ feedback_add_details("traitor_uplink_items_bought","CP")
+ if("/obj/item/weapon/storage/emp_kit")
+ feedback_add_details("traitor_uplink_items_bought","EM")
+ if("/obj/item/weapon/pen/paralysis")
+ feedback_add_details("traitor_uplink_items_bought","PP")
+ if("/obj/item/weapon/cartridge/syndicate")
+ feedback_add_details("traitor_uplink_items_bought","DC")
+ if("/obj/item/clothing/under/chameleon")
+ feedback_add_details("traitor_uplink_items_bought","CJ")
+ if("/obj/item/weapon/card/id/syndicate")
+ feedback_add_details("traitor_uplink_items_bought","AC")
+ if("/obj/item/weapon/card/emag")
+ feedback_add_details("traitor_uplink_items_bought","EC")
+ if("/obj/item/weapon/storage/syndie_kit/space")
+ feedback_add_details("traitor_uplink_items_bought","SS")
+ if("/obj/item/device/encryptionkey/binary")
+ feedback_add_details("traitor_uplink_items_bought","BT")
+ if("/obj/item/weapon/storage/syndie_kit/imp_freedom")
+ feedback_add_details("traitor_uplink_items_bought","FI")
+ if("/obj/item/clothing/glasses/thermal/syndi")
+ feedback_add_details("traitor_uplink_items_bought","TM")
+ if("/obj/item/ammo_magazine/a357")
+ feedback_add_details("traitor_uplink_items_bought","RA")
+ if("/obj/item/clothing/shoes/syndigaloshes")
+ feedback_add_details("traitor_uplink_items_bought","SH")
+ if("/obj/item/weapon/plastique")
+ feedback_add_details("traitor_uplink_items_bought","C4")
+ if("/obj/item/weapon/soap/syndie")
+ feedback_add_details("traitor_uplink_items_bought","SP")
+ if("/obj/item/weapon/storage/toolbox/syndicate")
+ feedback_add_details("traitor_uplink_items_bought","ST")
+
+/obj/item/device/uplink/Topic(href, href_list)
+
+ if (href_list["buy_item"])
+ if(href_list["buy_item"] == "random")
+ var/boughtItem = chooseRandomItem()
+ if(boughtItem)
+ href_list["buy_item"] = boughtItem
+ feedback_add_details("traitor_uplink_items_bought","RN")
+ return 1
+ else
+ return 0
+
+ else
+ if(text2num(href_list["cost"]) > uses) // Not enough crystals for the item
+ return 0
+
+ //if(usr:mind && ticker.mode.traitors[usr:mind])
+ //var/datum/traitorinfo/info = ticker.mode.traitors[usr:mind]
+ //info.spawnlist += href_list["buy_item"]
+
+ uses -= text2num(href_list["cost"])
+ handleStatTracking(href_list["buy_item"]) //Note: chooseRandomItem handles it's own stat tracking. This proc is not meant for 'random'.
+ return 1
+
+
+
+// HIDDEN UPLINK - Can be stored in anything but the host item has to have a trigger for it.
+/* How to create an uplink in 3 easy steps!
+
+ 1. All obj/item 's have a hidden_uplink var. By default it's null. Give the item one with "new(src)", it must be in it's contents. Feel free to add "uses".
+
+ 2. Code in the triggers. Use check_trigger for this, I recommend closing the item's menu with "usr << browse(null, "window=windowname") if it returns true.
+ The var/value is the value that will be compared with the var/target. If they are equal it will activate the menu.
+
+ 3. If you want the menu to stay until the users locks his uplink, add an active_uplink_check(mob/user as mob) in your interact/attack_hand proc.
+ Then check if it's true, if true return. This will stop the normal menu appearing and will instead show the uplink menu.
+*/
+
+/obj/item/device/uplink/hidden
+ name = "Hidden Uplink."
+ desc = "There is something wrong if you're examining this."
+ var/active = 0
+ var/list/purchase_log = list()
+
+// The hidden uplink MUST be inside an obj/item's contents.
+/obj/item/device/uplink/hidden/New()
+ spawn(2)
+ if(!istype(src.loc, /obj/item))
+ del(src)
+ ..()
+
+// Toggles the uplink on and off. Normally this will bypass the item's normal functions and go to the uplink menu, if activated.
+/obj/item/device/uplink/hidden/proc/toggle()
+ active = !active
+
+// Directly trigger the uplink. Turn on if it isn't already.
+/obj/item/device/uplink/hidden/proc/trigger(mob/user as mob)
+ if(!active)
+ toggle()
+ interact(user)
+
+// Checks to see if the value meets the target. Like a frequency being a traitor_frequency, in order to unlock a headset.
+// If true, it accesses trigger() and returns 1. If it fails, it returns false. Use this to see if you need to close the
+// current item's menu.
+/obj/item/device/uplink/hidden/proc/check_trigger(mob/user as mob, var/value, var/target)
+ if(value == target)
+ trigger(user)
+ return 1
+ return 0
+
+// Interaction code. Gathers a list of items purchasable from the paren't uplink and displays it. It also adds a lock button.
+/obj/item/device/uplink/hidden/proc/interact(mob/user as mob)
+
+ var/dat = ""
+ dat += src.generate_menu()
+ dat += "Lock"
+ dat += ""
+ user << browse(dat, "window=hidden")
+ onclose(user, "hidden")
+ return
+
+// The purchasing code.
+/obj/item/device/uplink/hidden/Topic(href, href_list)
+
+ if (usr.stat || usr.restrained())
+ return
+
+ if (!( istype(usr, /mob/living/carbon/human)))
+ return 0
+
+ if ((usr.contents.Find(src.loc) || (in_range(src.loc, usr) && istype(src.loc.loc, /turf))))
+ usr.machine = src
+ if(href_list["lock"])
+ toggle()
+ usr << browse(null, "window=hidden")
+ return 1
+
+ if(..(href, href_list) == 1)
+ var/path_obj = text2path(href_list["buy_item"])
+ var/obj/I = new path_obj(get_turf(usr))
+ if(ishuman(usr))
+ var/mob/living/carbon/human/A = usr
+ A.put_in_any_hand_if_possible(I)
+ purchase_log += "[usr] ([usr.ckey]) bought [I]."
+ interact(usr)
+ return
+
+// I placed this here because of how relevant it is.
+// You place this in your uplinkable item to check if an uplink is active or not.
+// If it is, it will display the uplink menu and return 1, else it'll return false.
+// If it returns true, I recommend closing the item's normal menu with "user << browse(null, "window=name")"
+/obj/item/proc/active_uplink_check(mob/user as mob)
+ // Activates the uplink if it's active
+ if(src.hidden_uplink)
+ if(src.hidden_uplink.active)
+ src.hidden_uplink.trigger(user)
+ return 1
+ return 0
+
+// PRESET UPLINKS
+// A collection of preset uplinks.
+//
+// Includes normal radio uplink, multitool uplink,
+// implant uplink (not the implant tool) and a preset headset uplink.
+
+/obj/item/device/radio/uplink/New()
+ hidden_uplink = new(src)
+ icon_state = "radio"
+
+/obj/item/device/radio/uplink/attack_self(mob/user as mob)
+ if(hidden_uplink)
+ hidden_uplink.trigger(user)
+
+/obj/item/device/multitool/uplink/New()
+ hidden_uplink = new(src)
+
+/obj/item/device/multitool/uplink/attack_self(mob/user as mob)
+ if(hidden_uplink)
+ hidden_uplink.trigger(user)
+
+/obj/item/device/radio/headset/uplink
+ traitor_frequency = 1445
+
+/obj/item/device/radio/headset/uplink/New()
+ ..()
+ hidden_uplink = new(src)
+ hidden_uplink.uses = 10
+
+
+
+>>>>>>> remotes/git-svn
diff --git a/code/game/objects/items/devices/violin.dm b/code/game/objects/items/devices/violin.dm
new file mode 100644
index 00000000000..2a9487e5b7f
--- /dev/null
+++ b/code/game/objects/items/devices/violin.dm
@@ -0,0 +1,393 @@
+//copy pasta of the space piano, don't hurt me -Pete
+
+/obj/item/device/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 = 'icons/obj/musician.dmi'
+ icon_state = "violin"
+ item_state = "violin"
+ force = 10
+ var/datum/song/song
+ var/playing = 0
+ var/help = 0
+ var/edit = 1
+ var/repeat = 0
+
+/obj/item/device/violin/proc/playnote(var/note as text)
+ //world << "Note: [note]"
+ var/soundfile
+ /*BYOND loads resource files at compile time if they are ''. This means you can't really manipulate them dynamically.
+ Tried doing it dynamically at first but its more trouble than its worth. Would have saved many lines tho.*/
+ switch(note)
+ if("Cn1") soundfile = 'sound/violin/Cn1.ogg'
+ if("C#1") soundfile = 'sound/violin/C#1.ogg'
+ if("Db1") soundfile = 'sound/violin/Db1.ogg'
+ if("Dn1") soundfile = 'sound/violin/Dn1.ogg'
+ if("D#1") soundfile = 'sound/violin/D#1.ogg'
+ if("Eb1") soundfile = 'sound/violin/Eb1.ogg'
+ if("En1") soundfile = 'sound/violin/En1.ogg'
+ if("E#1") soundfile = 'sound/violin/E#1.ogg'
+ if("Fb1") soundfile = 'sound/violin/Fb1.ogg'
+ if("Fn1") soundfile = 'sound/violin/Fn1.ogg'
+ if("F#1") soundfile = 'sound/violin/F#1.ogg'
+ if("Gb1") soundfile = 'sound/violin/Gb1.ogg'
+ if("Gn1") soundfile = 'sound/violin/Gn1.ogg'
+ if("G#1") soundfile = 'sound/violin/G#1.ogg'
+ if("Ab1") soundfile = 'sound/violin/Ab1.ogg'
+ if("An1") soundfile = 'sound/violin/An1.ogg'
+ if("A#1") soundfile = 'sound/violin/A#1.ogg'
+ if("Bb1") soundfile = 'sound/violin/Bb1.ogg'
+ if("Bn1") soundfile = 'sound/violin/Bn1.ogg'
+ if("B#1") soundfile = 'sound/violin/B#1.ogg'
+ if("Cb2") soundfile = 'sound/violin/Cb2.ogg'
+ if("Cn2") soundfile = 'sound/violin/Cn2.ogg'
+ if("C#2") soundfile = 'sound/violin/C#2.ogg'
+ if("Db2") soundfile = 'sound/violin/Db2.ogg'
+ if("Dn2") soundfile = 'sound/violin/Dn2.ogg'
+ if("D#2") soundfile = 'sound/violin/D#2.ogg'
+ if("Eb2") soundfile = 'sound/violin/Eb2.ogg'
+ if("En2") soundfile = 'sound/violin/En2.ogg'
+ if("E#2") soundfile = 'sound/violin/E#2.ogg'
+ if("Fb2") soundfile = 'sound/violin/Fb2.ogg'
+ if("Fn2") soundfile = 'sound/violin/Fn2.ogg'
+ if("F#2") soundfile = 'sound/violin/F#2.ogg'
+ if("Gb2") soundfile = 'sound/violin/Gb2.ogg'
+ if("Gn2") soundfile = 'sound/violin/Gn2.ogg'
+ if("G#2") soundfile = 'sound/violin/G#2.ogg'
+ if("Ab2") soundfile = 'sound/violin/Ab2.ogg'
+ if("An2") soundfile = 'sound/violin/An2.ogg'
+ if("A#2") soundfile = 'sound/violin/A#2.ogg'
+ if("Bb2") soundfile = 'sound/violin/Bb2.ogg'
+ if("Bn2") soundfile = 'sound/violin/Bn2.ogg'
+ if("B#2") soundfile = 'sound/violin/B#2.ogg'
+ if("Cb3") soundfile = 'sound/violin/Cb3.ogg'
+ if("Cn3") soundfile = 'sound/violin/Cn3.ogg'
+ if("C#3") soundfile = 'sound/violin/C#3.ogg'
+ if("Db3") soundfile = 'sound/violin/Db3.ogg'
+ if("Dn3") soundfile = 'sound/violin/Dn3.ogg'
+ if("D#3") soundfile = 'sound/violin/D#3.ogg'
+ if("Eb3") soundfile = 'sound/violin/Eb3.ogg'
+ if("En3") soundfile = 'sound/violin/En3.ogg'
+ if("E#3") soundfile = 'sound/violin/E#3.ogg'
+ if("Fb3") soundfile = 'sound/violin/Fb3.ogg'
+ if("Fn3") soundfile = 'sound/violin/Fn3.ogg'
+ if("F#3") soundfile = 'sound/violin/F#3.ogg'
+ if("Gb3") soundfile = 'sound/violin/Gb3.ogg'
+ if("Gn3") soundfile = 'sound/violin/Gn3.ogg'
+ if("G#3") soundfile = 'sound/violin/G#3.ogg'
+ if("Ab3") soundfile = 'sound/violin/Ab3.ogg'
+ if("An3") soundfile = 'sound/violin/An3.ogg'
+ if("A#3") soundfile = 'sound/violin/A#3.ogg'
+ if("Bb3") soundfile = 'sound/violin/Bb3.ogg'
+ if("Bn3") soundfile = 'sound/violin/Bn3.ogg'
+ if("B#3") soundfile = 'sound/violin/B#3.ogg'
+ if("Cb4") soundfile = 'sound/violin/Cb4.ogg'
+ if("Cn4") soundfile = 'sound/violin/Cn4.ogg'
+ if("C#4") soundfile = 'sound/violin/C#4.ogg'
+ if("Db4") soundfile = 'sound/violin/Db4.ogg'
+ if("Dn4") soundfile = 'sound/violin/Dn4.ogg'
+ if("D#4") soundfile = 'sound/violin/D#4.ogg'
+ if("Eb4") soundfile = 'sound/violin/Eb4.ogg'
+ if("En4") soundfile = 'sound/violin/En4.ogg'
+ if("E#4") soundfile = 'sound/violin/E#4.ogg'
+ if("Fb4") soundfile = 'sound/violin/Fb4.ogg'
+ if("Fn4") soundfile = 'sound/violin/Fn4.ogg'
+ if("F#4") soundfile = 'sound/violin/F#4.ogg'
+ if("Gb4") soundfile = 'sound/violin/Gb4.ogg'
+ if("Gn4") soundfile = 'sound/violin/Gn4.ogg'
+ if("G#4") soundfile = 'sound/violin/G#4.ogg'
+ if("Ab4") soundfile = 'sound/violin/Ab4.ogg'
+ if("An4") soundfile = 'sound/violin/An4.ogg'
+ if("A#4") soundfile = 'sound/violin/A#4.ogg'
+ if("Bb4") soundfile = 'sound/violin/Bb4.ogg'
+ if("Bn4") soundfile = 'sound/violin/Bn4.ogg'
+ if("B#4") soundfile = 'sound/violin/B#4.ogg'
+ if("Cb5") soundfile = 'sound/violin/Cb5.ogg'
+ if("Cn5") soundfile = 'sound/violin/Cn5.ogg'
+ if("C#5") soundfile = 'sound/violin/C#5.ogg'
+ if("Db5") soundfile = 'sound/violin/Db5.ogg'
+ if("Dn5") soundfile = 'sound/violin/Dn5.ogg'
+ if("D#5") soundfile = 'sound/violin/D#5.ogg'
+ if("Eb5") soundfile = 'sound/violin/Eb5.ogg'
+ if("En5") soundfile = 'sound/violin/En5.ogg'
+ if("E#5") soundfile = 'sound/violin/E#5.ogg'
+ if("Fb5") soundfile = 'sound/violin/Fb5.ogg'
+ if("Fn5") soundfile = 'sound/violin/Fn5.ogg'
+ if("F#5") soundfile = 'sound/violin/F#5.ogg'
+ if("Gb5") soundfile = 'sound/violin/Gb5.ogg'
+ if("Gn5") soundfile = 'sound/violin/Gn5.ogg'
+ if("G#5") soundfile = 'sound/violin/G#5.ogg'
+ if("Ab5") soundfile = 'sound/violin/Ab5.ogg'
+ if("An5") soundfile = 'sound/violin/An5.ogg'
+ if("A#5") soundfile = 'sound/violin/A#5.ogg'
+ if("Bb5") soundfile = 'sound/violin/Bb5.ogg'
+ if("Bn5") soundfile = 'sound/violin/Bn5.ogg'
+ if("B#5") soundfile = 'sound/violin/B#5.ogg'
+ if("Cb6") soundfile = 'sound/violin/Cb6.ogg'
+ if("Cn6") soundfile = 'sound/violin/Cn6.ogg'
+ if("C#6") soundfile = 'sound/violin/C#6.ogg'
+ if("Db6") soundfile = 'sound/violin/Db6.ogg'
+ if("Dn6") soundfile = 'sound/violin/Dn6.ogg'
+ if("D#6") soundfile = 'sound/violin/D#6.ogg'
+ if("Eb6") soundfile = 'sound/violin/Eb6.ogg'
+ if("En6") soundfile = 'sound/violin/En6.ogg'
+ if("E#6") soundfile = 'sound/violin/E#6.ogg'
+ if("Fb6") soundfile = 'sound/violin/Fb6.ogg'
+ if("Fn6") soundfile = 'sound/violin/Fn6.ogg'
+ if("F#6") soundfile = 'sound/violin/F#6.ogg'
+ if("Gb6") soundfile = 'sound/violin/Gb6.ogg'
+ if("Gn6") soundfile = 'sound/violin/Gn6.ogg'
+ if("G#6") soundfile = 'sound/violin/G#6.ogg'
+ if("Ab6") soundfile = 'sound/violin/Ab6.ogg'
+ if("An6") soundfile = 'sound/violin/An6.ogg'
+ if("A#6") soundfile = 'sound/violin/A#6.ogg'
+ if("Bb6") soundfile = 'sound/violin/Bb6.ogg'
+ if("Bn6") soundfile = 'sound/violin/Bn6.ogg'
+ if("B#6") soundfile = 'sound/violin/B#6.ogg'
+ if("Cb7") soundfile = 'sound/violin/Cb7.ogg'
+ if("Cn7") soundfile = 'sound/violin/Cn7.ogg'
+ if("C#7") soundfile = 'sound/violin/C#7.ogg'
+ if("Db7") soundfile = 'sound/violin/Db7.ogg'
+ if("Dn7") soundfile = 'sound/violin/Dn7.ogg'
+ if("D#7") soundfile = 'sound/violin/D#7.ogg'
+ if("Eb7") soundfile = 'sound/violin/Eb7.ogg'
+ if("En7") soundfile = 'sound/violin/En7.ogg'
+ if("E#7") soundfile = 'sound/violin/E#7.ogg'
+ if("Fb7") soundfile = 'sound/violin/Fb7.ogg'
+ if("Fn7") soundfile = 'sound/violin/Fn7.ogg'
+ if("F#7") soundfile = 'sound/violin/F#7.ogg'
+ if("Gb7") soundfile = 'sound/violin/Gb7.ogg'
+ if("Gn7") soundfile = 'sound/violin/Gn7.ogg'
+ if("G#7") soundfile = 'sound/violin/G#7.ogg'
+ if("Ab7") soundfile = 'sound/violin/Ab7.ogg'
+ if("An7") soundfile = 'sound/violin/An7.ogg'
+ if("A#7") soundfile = 'sound/violin/A#7.ogg'
+ if("Bb7") soundfile = 'sound/violin/Bb7.ogg'
+ if("Bn7") soundfile = 'sound/violin/Bn7.ogg'
+ if("B#7") soundfile = 'sound/violin/B#7.ogg'
+ if("Cb8") soundfile = 'sound/violin/Cb8.ogg'
+ if("Cn8") soundfile = 'sound/violin/Cn8.ogg'
+ if("C#8") soundfile = 'sound/violin/C#8.ogg'
+ if("Db8") soundfile = 'sound/violin/Db8.ogg'
+ if("Dn8") soundfile = 'sound/violin/Dn8.ogg'
+ if("D#8") soundfile = 'sound/violin/D#8.ogg'
+ if("Eb8") soundfile = 'sound/violin/Eb8.ogg'
+ if("En8") soundfile = 'sound/violin/En8.ogg'
+ if("E#8") soundfile = 'sound/violin/E#8.ogg'
+ if("Fb8") soundfile = 'sound/violin/Fb8.ogg'
+ if("Fn8") soundfile = 'sound/violin/Fn8.ogg'
+ if("F#8") soundfile = 'sound/violin/F#8.ogg'
+ if("Gb8") soundfile = 'sound/violin/Gb8.ogg'
+ if("Gn8") soundfile = 'sound/violin/Gn8.ogg'
+ if("G#8") soundfile = 'sound/violin/G#8.ogg'
+ if("Ab8") soundfile = 'sound/violin/Ab8.ogg'
+ if("An8") soundfile = 'sound/violin/An8.ogg'
+ if("A#8") soundfile = 'sound/violin/A#8.ogg'
+ if("Bb8") soundfile = 'sound/violin/Bb8.ogg'
+ if("Bn8") soundfile = 'sound/violin/Bn8.ogg'
+ if("B#8") soundfile = 'sound/violin/B#8.ogg'
+ if("Cb9") soundfile = 'sound/violin/Cb9.ogg'
+ if("Cn9") soundfile = 'sound/violin/Cn9.ogg'
+ else return
+
+ hearers(15, get_turf(src)) << sound(soundfile)
+
+/obj/item/device/violin/proc/playsong()
+ do
+ 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 song.lines)
+ //world << line
+ for(var/beat in dd_text2list(lowertext(line), ","))
+ //world << "beat: [beat]"
+ var/list/notes = dd_text2list(beat, "/")
+ for(var/note in dd_text2list(notes[1], "-"))
+ //world << "note: [note]"
+ if(!playing || !isliving(loc))//If the violin is playing, or isn't held by a person
+ playing = 0
+ return
+ if(lentext(note) == 0)
+ continue
+ //world << "Parse: [copytext(note,1,2)]"
+ var/cur_note = text2ascii(note) - 96
+ if(cur_note < 1 || cur_note > 7)
+ continue
+ for(var/i=2 to lentext(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] = ni
+ playnote(uppertext(copytext(note,1,2)) + cur_acc[cur_note] + cur_oct[cur_note])
+ if(notes.len >= 2 && text2num(notes[2]))
+ sleep(song.tempo / text2num(notes[2]))
+ else
+ sleep(song.tempo)
+ if(repeat > 0)
+ repeat-- //Infinite loops are baaaad.
+ while(repeat > 0)
+ playing = 0
+
+/obj/item/device/violin/attack_self(mob/user as mob)
+ if(!isliving(user) || user.stat || user.restrained() || user.lying) return
+ user.machine = src
+
+ var/dat = "Violin"
+
+ if(song)
+ if(song.lines.len > 0 && !(playing))
+ dat += "Play Song
"
+ dat += "Repeat Song: [repeat] times.
"
+ if(playing)
+ dat += "Stop Playing
"
+ dat += "Repeats left: [repeat].
"
+ if(!edit)
+ dat += "Show Editor
"
+ else
+ dat += "Hide Editor
"
+ dat += "Start a New Song
"
+ dat += "Import a Song
"
+ if(song)
+ var/calctempo = (10/song.tempo)*60
+ dat += "Tempo : -- [calctempo] BPM ++
"
+ var/linecount = 0
+ for(var/line in song.lines)
+ linecount += 1
+ dat += "Line [linecount]: [line] Delete Line Modify Line
"
+ dat += "Add Line
"
+ if(help)
+ dat += "Hide Help
"
+ dat += {"
+ Lines are a series of chords, separated by commas (,), each with notes seperated by hyphens (-).
+ Every note in a chord will play together, with chord timed by the tempo.
+
+ Notes are played by the names of the note, and optionally, the accidental, and/or the octave number.
+ By default, every note is natural and in octave 3. Defining otherwise is remembered for each note.
+ Example: C,D,E,F,G,A,B will play a C major scale.
+ After a note has an accidental placed, it will be remembered: C,C4,C,C3 is C3,C4,C4,C3
+ Chords can be played simply by seperating each note with a hyphon: A-C#,Cn-E,E-G#,Gn-B
+ A pause may be denoted by an empty chord: C,E,,C,G
+ To make a chord be a different time, end it with /x, where the chord length will be length
+ defined by tempo / x: C,G/2,E/4
+ Combined, an example is: E-E4/4,/2,G#/8,B/8,E3-E4/4
+
+ Lines may be up to 50 characters.
+ A song may only contain up to 50 lines.
+ "}
+ else
+ dat += "Show Help
"
+ dat += "