Merge remote-tracking branch 'remotes/git-svn' into bs12_with_tgport

Conflicts:
	code/controllers/configuration.dm
	code/game/atoms.dm
	code/game/gamemodes/changeling/modularchangling.dm
	code/game/gamemodes/factions.dm
	code/game/objects/items/devices/uplinks.dm
	code/game/verbs/ooc.dm
	code/game/verbs/who.dm
	code/modules/admin/admin.dm
	code/modules/admin/admin_verbs.dm
	code/modules/admin/player_panel.dm
	code/modules/admin/verbs/adminpm.dm
	code/modules/admin/verbs/getlogs.dm
	code/modules/client/client defines.dm
	code/modules/client/client procs.dm
	code/modules/mob/living/login.dm
	code/modules/mob/new_player/preferences_setup.dm
	code/modules/paperwork/paper.dm
	config/config.txt
	html/changelog.html
	icons/mob/human.dmi
	icons/mob/human_face.dmi

Signed-off-by: Cael_Aislinn <cael_aislinn@yahoo.com.au>
This commit is contained in:
Cael_Aislinn
2012-09-26 18:49:18 +10:00
303 changed files with 14307 additions and 12887 deletions
@@ -282,7 +282,6 @@ Code:
if (43) //Muskets' and Rockdtben's power monitor :D
menu = "<h4><img src=pda_power.png> Power Monitors - Please select one</h4><BR>"
powmonitor = null
powermonitors = null
powermonitors = list()
var/powercount = 0
@@ -47,7 +47,7 @@
A.loc = src
user << "<span class='notice'>You attach the [item] to the valve controls and secure it.</span>"
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.")
+378
View File
@@ -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 = "<B>[src.welcome]</B><BR>"
dat += "Tele-Crystals left: [src.uses]<BR>"
dat += "<HR>"
dat += "<B>Request item:</B><BR>"
dat += "<I>Each item costs a number of tele-crystals as indicated by the number following their name.</I><br><BR>"
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 += "<b>[O[1]]</b><br>"
category_items = 0
else //Else, it's a white space.
if(category_items < 1) //If there were no itens in the last category...
dat += "<i>We apologize, as you could not afford anything from this category.</i><br>"
dat += "<br>"
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 += "<A href='byond://?src=\ref[src];buy_item=[path_text];cost=[cost]'>[name]</A> ([cost])<BR>"
category_items++
dat += "<A href='byond://?src=\ref[src];buy_item=random'>Random Item (??)</A><br>"
dat += "<HR>"
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 = "<body link='yellow' alink='white' bgcolor='#601414'><font color='white'>"
dat += src.generate_menu()
dat += "<A href='byond://?src=\ref[src];lock=1'>Lock</a>"
dat += "</font></body>"
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
+393
View File
@@ -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 = "<HEAD><TITLE>Violin</TITLE></HEAD><BODY>"
if(song)
if(song.lines.len > 0 && !(playing))
dat += "<A href='?src=\ref[src];play=1'>Play Song</A><BR><BR>"
dat += "<A href='?src=\ref[src];repeat=1'>Repeat Song: [repeat] times.</A><BR><BR>"
if(playing)
dat += "<A href='?src=\ref[src];stop=1'>Stop Playing</A><BR>"
dat += "Repeats left: [repeat].<BR><BR>"
if(!edit)
dat += "<A href='?src=\ref[src];edit=2'>Show Editor</A><BR><BR>"
else
dat += "<A href='?src=\ref[src];edit=1'>Hide Editor</A><BR>"
dat += "<A href='?src=\ref[src];newsong=1'>Start a New Song</A><BR>"
dat += "<A href='?src=\ref[src];import=1'>Import a Song</A><BR><BR>"
if(song)
var/calctempo = (10/song.tempo)*60
dat += "Tempo : <A href='?src=\ref[src];tempo=10'>-</A><A href='?src=\ref[src];tempo=1'>-</A> [calctempo] BPM <A href='?src=\ref[src];tempo=-1'>+</A><A href='?src=\ref[src];tempo=-10'>+</A><BR><BR>"
var/linecount = 0
for(var/line in song.lines)
linecount += 1
dat += "Line [linecount]: [line] <A href='?src=\ref[src];deleteline=[linecount]'>Delete Line</A> <A href='?src=\ref[src];modifyline=[linecount]'>Modify Line</A><BR>"
dat += "<A href='?src=\ref[src];newline=1'>Add Line</A><BR><BR>"
if(help)
dat += "<A href='?src=\ref[src];help=1'>Hide Help</A><BR>"
dat += {"
Lines are a series of chords, separated by commas (,), each with notes seperated by hyphens (-).<br>
Every note in a chord will play together, with chord timed by the tempo.<br>
<br>
Notes are played by the names of the note, and optionally, the accidental, and/or the octave number.<br>
By default, every note is natural and in octave 3. Defining otherwise is remembered for each note.<br>
Example: <i>C,D,E,F,G,A,B</i> will play a C major scale.<br>
After a note has an accidental placed, it will be remembered: <i>C,C4,C,C3</i> is C3,C4,C4,C3</i><br>
Chords can be played simply by seperating each note with a hyphon: <i>A-C#,Cn-E,E-G#,Gn-B</i><br>
A pause may be denoted by an empty chord: <i>C,E,,C,G</i><br>
To make a chord be a different time, end it with /x, where the chord length will be length<br>
defined by tempo / x: <i>C,G/2,E/4</i><br>
Combined, an example is: <i>E-E4/4,/2,G#/8,B/8,E3-E4/4</i>
<br>
Lines may be up to 50 characters.<br>
A song may only contain up to 50 lines.<br>
"}
else
dat += "<A href='?src=\ref[src];help=2'>Show Help</A><BR>"
dat += "</BODY></HTML>"
user << browse(dat, "window=violin;size=700x300")
onclose(user, "violin")
/obj/item/device/violin/Topic(href, href_list)
if(!in_range(src, usr) || issilicon(usr) || !isliving(usr) || !usr.canmove || usr.restrained())
usr << browse(null, "window=violin;size=700x300")
onclose(usr, "violin")
return
if(href_list["newsong"])
song = new()
else if(song)
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.
var/tempnum = input("How many times do you want to repeat this piece? (max:10)") as num|null
if(tempnum > 10)
tempnum = 10
if(tempnum < 0)
tempnum = 0
repeat = round(tempnum)
else if(href_list["tempo"])
song.tempo += round(text2num(href_list["tempo"]))
if(song.tempo < 1)
song.tempo = 1
else if(href_list["play"])
if(song)
playing = 1
spawn() playsong()
else if(href_list["newline"])
var/newline = html_encode(input("Enter your line: ", "violin") as text|null)
if(!newline)
return
if(song.lines.len > 50)
return
if(lentext(newline) > 50)
newline = copytext(newline, 1, 50)
song.lines.Add(newline)
else if(href_list["deleteline"])
var/num = round(text2num(href_list["deleteline"]))
if(num > song.lines.len || num < 1)
return
song.lines.Cut(num, num+1)
else if(href_list["modifyline"])
var/num = round(text2num(href_list["modifyline"]),1)
var/content = html_encode(input("Enter your line: ", "violin", song.lines[num]) as text|null)
if(!content)
return
if(lentext(content) > 50)
content = copytext(content, 1, 50)
if(num > song.lines.len || num < 1)
return
song.lines[num] = content
else if(href_list["stop"])
playing = 0
else if(href_list["help"])
help = text2num(href_list["help"]) - 1
else if(href_list["edit"])
edit = text2num(href_list["edit"]) - 1
else if(href_list["import"])
var/t = ""
do
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message)
if(!in_range(src, usr))
return
if(lentext(t) >= 3072)
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(lentext(t) > 3072)
//split into lines
spawn()
var/list/lines = dd_text2list(t, "\n")
var/tempo = 5
if(copytext(lines[1],1,6) == "BPM: ")
tempo = 600 / text2num(copytext(lines[1],6))
lines.Cut(1,2)
if(lines.len > 50)
usr << "Too many lines!"
lines.Cut(51)
var/linenum = 1
for(var/l in lines)
if(lentext(l) > 50)
usr << "Line [linenum] too long!"
lines.Remove(l)
else
linenum++
song = new()
song.lines = lines
song.tempo = tempo
add_fingerprint(usr)
for(var/mob/M in viewers(1, loc))
if((M.client && M.machine == src))
attack_self(M)
return
@@ -0,0 +1,87 @@
/obj/item/weapon/lipstick
name = "red lipstick"
desc = "A generic brand of lipstick."
icon = 'icons/obj/items.dmi'
icon_state = "lipstick"
flags = FPRINT | TABLEPASS
w_class = 1.0
var/colour = "red"
var/open = 0
/obj/item/weapon/lipstick/purple
name = "purple lipstick"
colour = "purple"
/obj/item/weapon/lipstick/jade
name = "jade lipstick"
colour = "jade"
/obj/item/weapon/lipstick/black
name = "black lipstick"
colour = "black"
/obj/item/weapon/lipstick/random
name = "lipstick"
/obj/item/weapon/lipstick/random/New()
colour = pick("red","purple","jade","black")
name = "[colour] lipstick"
/obj/item/weapon/lipstick/attack_self(mob/user as mob)
user << "<span class='notice'>You twist \the [src] [open ? "closed" : "open"].</span>"
open = !open
if(open)
icon_state = "[initial(icon_state)]_[colour]"
else
icon_state = initial(icon_state)
/obj/item/weapon/lipstick/attack(mob/M as mob, mob/user as mob)
if(!open) return
if(!istype(M, /mob)) return
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.lip_style) //if they already have lipstick on
user << "<span class='notice'>You need to wipe off the old lipstick first!</span>"
return
if(H == user)
user.visible_message("<span class='notice'>[user] does their lips with \the [src].</span>", \
"<span class='notice'>You take a moment to apply \the [src]. Perfect!</span>")
H.lip_style = colour
H.update_body()
else
user.visible_message("<span class='warning'>[user] begins to do [H]'s lips with \the [src].</span>", \
"<span class='notice'>You begin to apply \the [src].</span>")
if(do_after(user, 20) && do_after(H, 20, 5, 0)) //user needs to keep their active hand, H does not.
user.visible_message("<span class='notice'>[user] does [H]'s lips with \the [src].</span>", \
"<span class='notice'>You apply \the [src].</span>")
H.lip_style = colour
H.update_body()
else
user << "<span class='notice'>Where are the lips on that?</span>"
//you can wipe off lipstick with paper!
/obj/item/weapon/paper/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
if(user.zone_sel.selecting == "mouth")
if(!istype(M, /mob)) return
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H == user)
user << "<span class='notice'>You wipe off the lipstick with [src].</span>"
H.lip_style = null
H.update_body()
else
user.visible_message("<span class='warning'>[user] begins to wipe [H]'s lipstick off with \the [src].</span>", \
"<span class='notice'>You begin to wipe off [H]'s lipstick.</span>")
if(do_after(user, 10) && do_after(H, 10, 5, 0)) //user needs to keep their active hand, H does not.
user.visible_message("<span class='notice'>[user] wipes [H]'s lipstick off with \the [src].</span>", \
"<span class='notice'>You wipe off [H]'s lipstick.</span>")
H.lip_style = null
H.update_body()
else
..()
+14 -29
View File
@@ -3,8 +3,6 @@
name = "mop"
icon = 'icons/obj/janitor.dmi'
icon_state = "mop"
var/mopping = 0
var/mopcount = 0
force = 3.0
throwforce = 10.0
throw_speed = 5
@@ -12,6 +10,8 @@
w_class = 3.0
flags = FPRINT | TABLEPASS
attack_verb = list("mopped", "bashed", "bludgeoned", "whacked")
var/mopping = 0
var/mopcount = 0
/obj/item/weapon/mop/New()
@@ -21,7 +21,7 @@
obj/item/weapon/mop/proc/clean(turf/simulated/A as turf)
src.reagents.reaction(A,1,10)
reagents.reaction(A,1,10)
A.clean_blood()
for(var/obj/effect/O in A)
if( istype(O,/obj/effect/rune) || istype(O,/obj/effect/decal/cleanable) || istype(O,/obj/effect/overlay) )
@@ -35,35 +35,20 @@ obj/item/weapon/mop/proc/clean(turf/simulated/A as turf)
/obj/item/weapon/mop/afterattack(atom/A, mob/user as mob)
if (src.reagents.total_volume < 1 || mopcount >= 5)
user << "\blue Your mop is dry!"
if(reagents.total_volume < 1 || mopcount >= 5)
user << "<span class='notice'>Your mop is dry!</span>"
return
if (istype(A, /turf/simulated))
for(var/mob/O in viewers(user, null))
O.show_message("\red <B>[user] begins to clean \the [A]</B>", 1)
sleep(40)
if(A)
clean(A)
user << "\blue You have finished mopping!"
mopcount++
else if (istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/overlay) || istype(A, /obj/effect/rune))
for(var/mob/O in viewers(user, null))
O.show_message("\red <B>[user] begins to clean \the [get_turf(A)]</B>", 1)
sleep(40)
if(A)
clean(get_turf(A))
user << "\blue You have finished mopping!"
mopcount++
if(istype(A, /turf/simulated) || istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/overlay) || istype(A, /obj/effect/rune))
user.visible_message("<span class='warning'>[user] begins to clean \the [get_turf(A)].</span>")
if(do_after(user, 40))
if(A)
clean(get_turf(A))
user << "<span class='notice'>You have finished mopping!</span>"
mopcount++
if(mopcount >= 5) //Okay this stuff is an ugly hack and i feel bad about it.
spawn(5)
src.reagents.clear_reagents()
reagents.clear_reagents()
mopcount = 0
return
return
-1
View File
@@ -7,7 +7,6 @@
var/reliability = 100 //Used by SOME devices to determine how reliable they are.
var/crit_fail = 0
var/unacidable = 0 //universal "unacidabliness" var, here so you can use it in any obj.
var/datum/marked_datum
animate_movement = 2
var/throwforce = 1
var/list/attack_verb = list() //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]"
@@ -34,6 +34,7 @@
if(!broken)
if(prob(50/severity))
src.locked = !src.locked
src.update_icon()
if(prob(20/severity) && !opened)
if(!locked)
open()
+579 -355
View File
@@ -2,305 +2,514 @@
/datum/song
var/name = "Untitled"
var/list/lines = new()
var/sourcestring = ""
var/compiledstring = ""
var/compilesuccess = 0
//For those other infidels who uses this datum
//VIOLINSSS
var/list/lines
var/tempo = 5
var/global/gid = 1
var/id = 0
New()
id = gid
gid++;
//Same text2list, but 20000 cap instead of 1000
/proc/dd_text2list_highcap(text, separator, var/list/withinList)
var/textlength = length(text)
var/separatorlength = length(separator)
if(withinList && !withinList.len) withinList = null
var/list/textList = new()
var/searchPosition = 1
var/findPosition = 1
var/loops = 0
while(1)
if(loops >= 20000)
break
loops++
findPosition = findtext(text, separator, searchPosition, 0)
var/buggyText = copytext(text, searchPosition, findPosition)
if(!withinList || (buggyText in withinList)) textList += "[buggyText]"
if(!findPosition) return textList
searchPosition = findPosition + separatorlength
if(searchPosition > textlength)
textList += ""
return textList
return
/obj/structure/device/piano
name = "space minimoog"
icon = 'icons/obj/musician.dmi'
icon_state = "minimoog"
anchored = 1
density = 1
var/datum/song/song
var/datum/song/currentsong = new()
var/list/internalsongs = new()
var/playing = 0
var/help = 0
var/edit = 1
var/repeat = 0
var/repeat = 1
/obj/structure/device/piano/New()
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"
var/showcontrol = 1
var/showeditor = 0
var/showhelp = 0
/obj/structure/device/piano/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/piano/Cn1.ogg'
if("C#1") soundfile = 'sound/piano/C#1.ogg'
if("Db1") soundfile = 'sound/piano/Db1.ogg'
if("Dn1") soundfile = 'sound/piano/Dn1.ogg'
if("D#1") soundfile = 'sound/piano/D#1.ogg'
if("Eb1") soundfile = 'sound/piano/Eb1.ogg'
if("En1") soundfile = 'sound/piano/En1.ogg'
if("E#1") soundfile = 'sound/piano/E#1.ogg'
if("Fb1") soundfile = 'sound/piano/Fb1.ogg'
if("Fn1") soundfile = 'sound/piano/Fn1.ogg'
if("F#1") soundfile = 'sound/piano/F#1.ogg'
if("Gb1") soundfile = 'sound/piano/Gb1.ogg'
if("Gn1") soundfile = 'sound/piano/Gn1.ogg'
if("G#1") soundfile = 'sound/piano/G#1.ogg'
if("Ab1") soundfile = 'sound/piano/Ab1.ogg'
if("An1") soundfile = 'sound/piano/An1.ogg'
if("A#1") soundfile = 'sound/piano/A#1.ogg'
if("Bb1") soundfile = 'sound/piano/Bb1.ogg'
if("Bn1") soundfile = 'sound/piano/Bn1.ogg'
if("B#1") soundfile = 'sound/piano/B#1.ogg'
if("Cb2") soundfile = 'sound/piano/Cb2.ogg'
if("Cn2") soundfile = 'sound/piano/Cn2.ogg'
if("C#2") soundfile = 'sound/piano/C#2.ogg'
if("Db2") soundfile = 'sound/piano/Db2.ogg'
if("Dn2") soundfile = 'sound/piano/Dn2.ogg'
if("D#2") soundfile = 'sound/piano/D#2.ogg'
if("Eb2") soundfile = 'sound/piano/Eb2.ogg'
if("En2") soundfile = 'sound/piano/En2.ogg'
if("E#2") soundfile = 'sound/piano/E#2.ogg'
if("Fb2") soundfile = 'sound/piano/Fb2.ogg'
if("Fn2") soundfile = 'sound/piano/Fn2.ogg'
if("F#2") soundfile = 'sound/piano/F#2.ogg'
if("Gb2") soundfile = 'sound/piano/Gb2.ogg'
if("Gn2") soundfile = 'sound/piano/Gn2.ogg'
if("G#2") soundfile = 'sound/piano/G#2.ogg'
if("Ab2") soundfile = 'sound/piano/Ab2.ogg'
if("An2") soundfile = 'sound/piano/An2.ogg'
if("A#2") soundfile = 'sound/piano/A#2.ogg'
if("Bb2") soundfile = 'sound/piano/Bb2.ogg'
if("Bn2") soundfile = 'sound/piano/Bn2.ogg'
if("B#2") soundfile = 'sound/piano/B#2.ogg'
if("Cb3") soundfile = 'sound/piano/Cb3.ogg'
if("Cn3") soundfile = 'sound/piano/Cn3.ogg'
if("C#3") soundfile = 'sound/piano/C#3.ogg'
if("Db3") soundfile = 'sound/piano/Db3.ogg'
if("Dn3") soundfile = 'sound/piano/Dn3.ogg'
if("D#3") soundfile = 'sound/piano/D#3.ogg'
if("Eb3") soundfile = 'sound/piano/Eb3.ogg'
if("En3") soundfile = 'sound/piano/En3.ogg'
if("E#3") soundfile = 'sound/piano/E#3.ogg'
if("Fb3") soundfile = 'sound/piano/Fb3.ogg'
if("Fn3") soundfile = 'sound/piano/Fn3.ogg'
if("F#3") soundfile = 'sound/piano/F#3.ogg'
if("Gb3") soundfile = 'sound/piano/Gb3.ogg'
if("Gn3") soundfile = 'sound/piano/Gn3.ogg'
if("G#3") soundfile = 'sound/piano/G#3.ogg'
if("Ab3") soundfile = 'sound/piano/Ab3.ogg'
if("An3") soundfile = 'sound/piano/An3.ogg'
if("A#3") soundfile = 'sound/piano/A#3.ogg'
if("Bb3") soundfile = 'sound/piano/Bb3.ogg'
if("Bn3") soundfile = 'sound/piano/Bn3.ogg'
if("B#3") soundfile = 'sound/piano/B#3.ogg'
if("Cb4") soundfile = 'sound/piano/Cb4.ogg'
if("Cn4") soundfile = 'sound/piano/Cn4.ogg'
if("C#4") soundfile = 'sound/piano/C#4.ogg'
if("Db4") soundfile = 'sound/piano/Db4.ogg'
if("Dn4") soundfile = 'sound/piano/Dn4.ogg'
if("D#4") soundfile = 'sound/piano/D#4.ogg'
if("Eb4") soundfile = 'sound/piano/Eb4.ogg'
if("En4") soundfile = 'sound/piano/En4.ogg'
if("E#4") soundfile = 'sound/piano/E#4.ogg'
if("Fb4") soundfile = 'sound/piano/Fb4.ogg'
if("Fn4") soundfile = 'sound/piano/Fn4.ogg'
if("F#4") soundfile = 'sound/piano/F#4.ogg'
if("Gb4") soundfile = 'sound/piano/Gb4.ogg'
if("Gn4") soundfile = 'sound/piano/Gn4.ogg'
if("G#4") soundfile = 'sound/piano/G#4.ogg'
if("Ab4") soundfile = 'sound/piano/Ab4.ogg'
if("An4") soundfile = 'sound/piano/An4.ogg'
if("A#4") soundfile = 'sound/piano/A#4.ogg'
if("Bb4") soundfile = 'sound/piano/Bb4.ogg'
if("Bn4") soundfile = 'sound/piano/Bn4.ogg'
if("B#4") soundfile = 'sound/piano/B#4.ogg'
if("Cb5") soundfile = 'sound/piano/Cb5.ogg'
if("Cn5") soundfile = 'sound/piano/Cn5.ogg'
if("C#5") soundfile = 'sound/piano/C#5.ogg'
if("Db5") soundfile = 'sound/piano/Db5.ogg'
if("Dn5") soundfile = 'sound/piano/Dn5.ogg'
if("D#5") soundfile = 'sound/piano/D#5.ogg'
if("Eb5") soundfile = 'sound/piano/Eb5.ogg'
if("En5") soundfile = 'sound/piano/En5.ogg'
if("E#5") soundfile = 'sound/piano/E#5.ogg'
if("Fb5") soundfile = 'sound/piano/Fb5.ogg'
if("Fn5") soundfile = 'sound/piano/Fn5.ogg'
if("F#5") soundfile = 'sound/piano/F#5.ogg'
if("Gb5") soundfile = 'sound/piano/Gb5.ogg'
if("Gn5") soundfile = 'sound/piano/Gn5.ogg'
if("G#5") soundfile = 'sound/piano/G#5.ogg'
if("Ab5") soundfile = 'sound/piano/Ab5.ogg'
if("An5") soundfile = 'sound/piano/An5.ogg'
if("A#5") soundfile = 'sound/piano/A#5.ogg'
if("Bb5") soundfile = 'sound/piano/Bb5.ogg'
if("Bn5") soundfile = 'sound/piano/Bn5.ogg'
if("B#5") soundfile = 'sound/piano/B#5.ogg'
if("Cb6") soundfile = 'sound/piano/Cb6.ogg'
if("Cn6") soundfile = 'sound/piano/Cn6.ogg'
if("C#6") soundfile = 'sound/piano/C#6.ogg'
if("Db6") soundfile = 'sound/piano/Db6.ogg'
if("Dn6") soundfile = 'sound/piano/Dn6.ogg'
if("D#6") soundfile = 'sound/piano/D#6.ogg'
if("Eb6") soundfile = 'sound/piano/Eb6.ogg'
if("En6") soundfile = 'sound/piano/En6.ogg'
if("E#6") soundfile = 'sound/piano/E#6.ogg'
if("Fb6") soundfile = 'sound/piano/Fb6.ogg'
if("Fn6") soundfile = 'sound/piano/Fn6.ogg'
if("F#6") soundfile = 'sound/piano/F#6.ogg'
if("Gb6") soundfile = 'sound/piano/Gb6.ogg'
if("Gn6") soundfile = 'sound/piano/Gn6.ogg'
if("G#6") soundfile = 'sound/piano/G#6.ogg'
if("Ab6") soundfile = 'sound/piano/Ab6.ogg'
if("An6") soundfile = 'sound/piano/An6.ogg'
if("A#6") soundfile = 'sound/piano/A#6.ogg'
if("Bb6") soundfile = 'sound/piano/Bb6.ogg'
if("Bn6") soundfile = 'sound/piano/Bn6.ogg'
if("B#6") soundfile = 'sound/piano/B#6.ogg'
if("Cb7") soundfile = 'sound/piano/Cb7.ogg'
if("Cn7") soundfile = 'sound/piano/Cn7.ogg'
if("C#7") soundfile = 'sound/piano/C#7.ogg'
if("Db7") soundfile = 'sound/piano/Db7.ogg'
if("Dn7") soundfile = 'sound/piano/Dn7.ogg'
if("D#7") soundfile = 'sound/piano/D#7.ogg'
if("Eb7") soundfile = 'sound/piano/Eb7.ogg'
if("En7") soundfile = 'sound/piano/En7.ogg'
if("E#7") soundfile = 'sound/piano/E#7.ogg'
if("Fb7") soundfile = 'sound/piano/Fb7.ogg'
if("Fn7") soundfile = 'sound/piano/Fn7.ogg'
if("F#7") soundfile = 'sound/piano/F#7.ogg'
if("Gb7") soundfile = 'sound/piano/Gb7.ogg'
if("Gn7") soundfile = 'sound/piano/Gn7.ogg'
if("G#7") soundfile = 'sound/piano/G#7.ogg'
if("Ab7") soundfile = 'sound/piano/Ab7.ogg'
if("An7") soundfile = 'sound/piano/An7.ogg'
if("A#7") soundfile = 'sound/piano/A#7.ogg'
if("Bb7") soundfile = 'sound/piano/Bb7.ogg'
if("Bn7") soundfile = 'sound/piano/Bn7.ogg'
if("B#7") soundfile = 'sound/piano/B#7.ogg'
if("Cb8") soundfile = 'sound/piano/Cb8.ogg'
if("Cn8") soundfile = 'sound/piano/Cn8.ogg'
if("C#8") soundfile = 'sound/piano/C#8.ogg'
if("Db8") soundfile = 'sound/piano/Db8.ogg'
if("Dn8") soundfile = 'sound/piano/Dn8.ogg'
if("D#8") soundfile = 'sound/piano/D#8.ogg'
if("Eb8") soundfile = 'sound/piano/Eb8.ogg'
if("En8") soundfile = 'sound/piano/En8.ogg'
if("E#8") soundfile = 'sound/piano/E#8.ogg'
if("Fb8") soundfile = 'sound/piano/Fb8.ogg'
if("Fn8") soundfile = 'sound/piano/Fn8.ogg'
if("F#8") soundfile = 'sound/piano/F#8.ogg'
if("Gb8") soundfile = 'sound/piano/Gb8.ogg'
if("Gn8") soundfile = 'sound/piano/Gn8.ogg'
if("G#8") soundfile = 'sound/piano/G#8.ogg'
if("Ab8") soundfile = 'sound/piano/Ab8.ogg'
if("An8") soundfile = 'sound/piano/An8.ogg'
if("A#8") soundfile = 'sound/piano/A#8.ogg'
if("Bb8") soundfile = 'sound/piano/Bb8.ogg'
if("Bn8") soundfile = 'sound/piano/Bn8.ogg'
if("B#8") soundfile = 'sound/piano/B#8.ogg'
if("Cb9") soundfile = 'sound/piano/Cb9.ogg'
if("Cn9") soundfile = 'sound/piano/Cn9.ogg'
else return
var/status = "Ok"
hearers(15, src) << sound(soundfile)
var/global/list/soundlist = new()
/obj/structure/device/piano/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"
New()
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"
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 || !anchored)//If the piano is playing, or is loose
playing = 0
//This shit is not used anywhere, but is needed to cache the sounds
soundlist["Cn1"] = 'sound/piano/Cn1.ogg'
soundlist["C#1"] = 'sound/piano/C#1.ogg'
//soundlist["Db1"] = 'sound/piano/Db1.ogg'
soundlist["Dn1"] = 'sound/piano/Dn1.ogg'
soundlist["D#1"] = 'sound/piano/D#1.ogg'
//soundlist["Eb1"] = 'sound/piano/Eb1.ogg'
soundlist["En1"] = 'sound/piano/En1.ogg'
soundlist["E#1"] = 'sound/piano/E#1.ogg'
//soundlist["Fb1"] = 'sound/piano/Fb1.ogg'
soundlist["Fn1"] = 'sound/piano/Fn1.ogg'
soundlist["F#1"] = 'sound/piano/F#1.ogg'
//soundlist["Gb1"] = 'sound/piano/Gb1.ogg'
soundlist["Gn1"] = 'sound/piano/Gn1.ogg'
soundlist["G#1"] = 'sound/piano/G#1.ogg'
//soundlist["Ab1"] = 'sound/piano/Ab1.ogg'
soundlist["An1"] = 'sound/piano/An1.ogg'
soundlist["A#1"] = 'sound/piano/A#1.ogg'
//soundlist["Bb1"] = 'sound/piano/Bb1.ogg'
soundlist["Bn1"] = 'sound/piano/Bn1.ogg'
soundlist["B#1"] = 'sound/piano/B#1.ogg'
soundlist["Cb2"] = 'sound/piano/Cb2.ogg'
soundlist["Cn2"] = 'sound/piano/Cn2.ogg'
soundlist["C#2"] = 'sound/piano/C#2.ogg'
//soundlist["Db2"] = 'sound/piano/Db2.ogg'
soundlist["Dn2"] = 'sound/piano/Dn2.ogg'
soundlist["D#2"] = 'sound/piano/D#2.ogg'
//soundlist["Eb2"] = 'sound/piano/Eb2.ogg'
soundlist["En2"] = 'sound/piano/En2.ogg'
soundlist["E#2"] = 'sound/piano/E#2.ogg'
//soundlist["Fb2"] = 'sound/piano/Fb2.ogg'
soundlist["Fn2"] = 'sound/piano/Fn2.ogg'
soundlist["F#2"] = 'sound/piano/F#2.ogg'
//soundlist["Gb2"] = 'sound/piano/Gb2.ogg'
soundlist["Gn2"] = 'sound/piano/Gn2.ogg'
soundlist["G#2"] = 'sound/piano/G#2.ogg'
//soundlist["Ab2"] = 'sound/piano/Ab2.ogg'
soundlist["An2"] = 'sound/piano/An2.ogg'
soundlist["A#2"] = 'sound/piano/A#2.ogg'
//soundlist["Bb2"] = 'sound/piano/Bb2.ogg'
soundlist["Bn2"] = 'sound/piano/Bn2.ogg'
soundlist["B#2"] = 'sound/piano/B#2.ogg'
soundlist["Cb3"] = 'sound/piano/Cb3.ogg'
soundlist["Cn3"] = 'sound/piano/Cn3.ogg'
soundlist["C#3"] = 'sound/piano/C#3.ogg'
//soundlist["Db3"] = 'sound/piano/Db3.ogg'
soundlist["Dn3"] = 'sound/piano/Dn3.ogg'
soundlist["D#3"] = 'sound/piano/D#3.ogg'
//soundlist["Eb3"] = 'sound/piano/Eb3.ogg'
soundlist["En3"] = 'sound/piano/En3.ogg'
soundlist["E#3"] = 'sound/piano/E#3.ogg'
//soundlist["Fb3"] = 'sound/piano/Fb3.ogg'
soundlist["Fn3"] = 'sound/piano/Fn3.ogg'
soundlist["F#3"] = 'sound/piano/F#3.ogg'
//soundlist["Gb3"] = 'sound/piano/Gb3.ogg'
soundlist["Gn3"] = 'sound/piano/Gn3.ogg'
soundlist["G#3"] = 'sound/piano/G#3.ogg'
//soundlist["Ab3"] = 'sound/piano/Ab3.ogg'
soundlist["An3"] = 'sound/piano/An3.ogg'
soundlist["A#3"] = 'sound/piano/A#3.ogg'
//soundlist["Bb3"] = 'sound/piano/Bb3.ogg'
soundlist["Bn3"] = 'sound/piano/Bn3.ogg'
soundlist["B#3"] = 'sound/piano/B#3.ogg'
soundlist["Cb4"] = 'sound/piano/Cb4.ogg'
soundlist["Cn4"] = 'sound/piano/Cn4.ogg'
soundlist["C#4"] = 'sound/piano/C#4.ogg'
//soundlist["Db4"] = 'sound/piano/Db4.ogg'
soundlist["Dn4"] = 'sound/piano/Dn4.ogg'
soundlist["D#4"] = 'sound/piano/D#4.ogg'
//soundlist["Eb4"] = 'sound/piano/Eb4.ogg'
soundlist["En4"] = 'sound/piano/En4.ogg'
soundlist["E#4"] = 'sound/piano/E#4.ogg'
//soundlist["Fb4"] = 'sound/piano/Fb4.ogg'
soundlist["Fn4"] = 'sound/piano/Fn4.ogg'
soundlist["F#4"] = 'sound/piano/F#4.ogg'
//soundlist["Gb4"] = 'sound/piano/Gb4.ogg'
soundlist["Gn4"] = 'sound/piano/Gn4.ogg'
soundlist["G#4"] = 'sound/piano/G#4.ogg'
//soundlist["Ab4"] = 'sound/piano/Ab4.ogg'
soundlist["An4"] = 'sound/piano/An4.ogg'
soundlist["A#4"] = 'sound/piano/A#4.ogg'
//soundlist["Bb4"] = 'sound/piano/Bb4.ogg'
soundlist["Bn4"] = 'sound/piano/Bn4.ogg'
soundlist["B#4"] = 'sound/piano/B#4.ogg'
soundlist["Cb5"] = 'sound/piano/Cb5.ogg'
soundlist["Cn5"] = 'sound/piano/Cn5.ogg'
soundlist["C#5"] = 'sound/piano/C#5.ogg'
//soundlist["Db5"] = 'sound/piano/Db5.ogg'
soundlist["Dn5"] = 'sound/piano/Dn5.ogg'
soundlist["D#5"] = 'sound/piano/D#5.ogg'
//soundlist["Eb5"] = 'sound/piano/Eb5.ogg'
soundlist["En5"] = 'sound/piano/En5.ogg'
soundlist["E#5"] = 'sound/piano/E#5.ogg'
//soundlist["Fb5"] = 'sound/piano/Fb5.ogg'
soundlist["Fn5"] = 'sound/piano/Fn5.ogg'
soundlist["F#5"] = 'sound/piano/F#5.ogg'
//soundlist["Gb5"] = 'sound/piano/Gb5.ogg'
soundlist["Gn5"] = 'sound/piano/Gn5.ogg'
soundlist["G#5"] = 'sound/piano/G#5.ogg'
//soundlist["Ab5"] = 'sound/piano/Ab5.ogg'
soundlist["An5"] = 'sound/piano/An5.ogg'
soundlist["A#5"] = 'sound/piano/A#5.ogg'
//soundlist["Bb5"] = 'sound/piano/Bb5.ogg'
soundlist["Bn5"] = 'sound/piano/Bn5.ogg'
soundlist["B#5"] = 'sound/piano/B#5.ogg'
soundlist["Cb6"] = 'sound/piano/Cb6.ogg'
soundlist["Cn6"] = 'sound/piano/Cn6.ogg'
soundlist["C#6"] = 'sound/piano/C#6.ogg'
//soundlist["Db6"] = 'sound/piano/Db6.ogg'
soundlist["Dn6"] = 'sound/piano/Dn6.ogg'
soundlist["D#6"] = 'sound/piano/D#6.ogg'
//soundlist["Eb6"] = 'sound/piano/Eb6.ogg'
soundlist["En6"] = 'sound/piano/En6.ogg'
soundlist["E#6"] = 'sound/piano/E#6.ogg'
//soundlist["Fb6"] = 'sound/piano/Fb6.ogg'
soundlist["Fn6"] = 'sound/piano/Fn6.ogg'
soundlist["F#6"] = 'sound/piano/F#6.ogg'
//soundlist["Gb6"] = 'sound/piano/Gb6.ogg'
soundlist["Gn6"] = 'sound/piano/Gn6.ogg'
soundlist["G#6"] = 'sound/piano/G#6.ogg'
//soundlist["Ab6"] = 'sound/piano/Ab6.ogg'
soundlist["An6"] = 'sound/piano/An6.ogg'
soundlist["A#6"] = 'sound/piano/A#6.ogg'
//soundlist["Bb6"] = 'sound/piano/Bb6.ogg'
soundlist["Bn6"] = 'sound/piano/Bn6.ogg'
soundlist["B#6"] = 'sound/piano/B#6.ogg'
soundlist["Cb7"] = 'sound/piano/Cb7.ogg'
soundlist["Cn7"] = 'sound/piano/Cn7.ogg'
soundlist["C#7"] = 'sound/piano/C#7.ogg'
//soundlist["Db7"] = 'sound/piano/Db7.ogg'
soundlist["Dn7"] = 'sound/piano/Dn7.ogg'
soundlist["D#7"] = 'sound/piano/D#7.ogg'
//soundlist["Eb7"] = 'sound/piano/Eb7.ogg'
soundlist["En7"] = 'sound/piano/En7.ogg'
soundlist["E#7"] = 'sound/piano/E#7.ogg'
//soundlist["Fb7"] = 'sound/piano/Fb7.ogg'
soundlist["Fn7"] = 'sound/piano/Fn7.ogg'
soundlist["F#7"] = 'sound/piano/F#7.ogg'
//soundlist["Gb7"] = 'sound/piano/Gb7.ogg'
soundlist["Gn7"] = 'sound/piano/Gn7.ogg'
soundlist["G#7"] = 'sound/piano/G#7.ogg'
//soundlist["Ab7"] = 'sound/piano/Ab7.ogg'
soundlist["An7"] = 'sound/piano/An7.ogg'
soundlist["A#7"] = 'sound/piano/A#7.ogg'
//soundlist["Bb7"] = 'sound/piano/Bb7.ogg'
soundlist["Bn7"] = 'sound/piano/Bn7.ogg'
soundlist["B#7"] = 'sound/piano/B#7.ogg'
soundlist["Cb8"] = 'sound/piano/Cb8.ogg'
soundlist["Cn8"] = 'sound/piano/Cn8.ogg'
soundlist["C#8"] = 'sound/piano/C#8.ogg'
//soundlist["Db8"] = 'sound/piano/Db8.ogg'
soundlist["Dn8"] = 'sound/piano/Dn8.ogg'
soundlist["D#8"] = 'sound/piano/D#8.ogg'
//soundlist["Eb8"] = 'sound/piano/Eb8.ogg'
soundlist["En8"] = 'sound/piano/En8.ogg'
soundlist["E#8"] = 'sound/piano/E#8.ogg'
//soundlist["Fb8"] = 'sound/piano/Fb8.ogg'
soundlist["Fn8"] = 'sound/piano/Fn8.ogg'
soundlist["F#8"] = 'sound/piano/F#8.ogg'
//soundlist["Gb8"] = 'sound/piano/Gb8.ogg'
soundlist["Gn8"] = 'sound/piano/Gn8.ogg'
soundlist["G#8"] = 'sound/piano/G#8.ogg'
//soundlist["Ab8"] = 'sound/piano/Ab8.ogg'
soundlist["An8"] = 'sound/piano/An8.ogg'
soundlist["A#8"] = 'sound/piano/A#8.ogg'
//soundlist["Bb8"] = 'sound/piano/Bb8.ogg'
soundlist["Bn8"] = 'sound/piano/Bn8.ogg'
soundlist["B#8"] = 'sound/piano/B#8.ogg'
soundlist["Cb9"] = 'sound/piano/Cb9.ogg'
soundlist["Cn9"] = 'sound/piano/Cn9.ogg'
proc/statusmsg( var/txt as text )
status = txt
updateUsrDialog()
proc/playsong()
if(currentsong.compilesuccess == 0)
playing = 0
statusmsg("Playback Error: Compile it first!")
return
var/list/tokens = dd_text2list_highcap(currentsong.compiledstring, "¤")
//Remove last token
tokens.Cut(tokens.len-1)
var/repetitions = 0
while(repetitions < repeat)
repetitions++
for(var/token in tokens)
if(playing == 0)
updateUsrDialog()
return
var/type = copytext(token, 1, 2)
switch(type)
if("x")
var/soundfile = copytext(token, 2)
soundfile = "sound/piano/[soundfile].ogg"
hearers(15, src) << sound(soundfile)
if("y")
sleep(text2num(copytext(token, 2)))
playing = 0
updateUsrDialog()
proc/compilesong()
var/compilestring = ""
var/strippedsourcestring = dd_replacetext(currentsong.sourcestring, "\n", "")
for(var/part in dd_text2list(strippedsourcestring, ","))
var/list/x = dd_text2list(part, "/")
var/xlen = x.len
var/list/tones = dd_text2list(x[1], "-")
var/tempodiv = 1
if(xlen==2)
tempodiv = text2num(x[2])
if(tempodiv == 0)
statusmsg( "Compile Error: Can't divide by 0!\nAt Part:'[part]' Tone:" )
return
else if(xlen>2)
statusmsg( "Compile Error: Tempo Syntax Error!\nAt Part:'[part]' Tone:" )
return
for(var/tone in tones)
var/len = lentext(tone)
if(len==0)
break
else if(len>3)
statusmsg( "Compile Error: Tone Syntax Error!\nAt Part:'[part]' Tone:'[tone]'" )
return
var/note = copytext(tone, 1, 2)
var/accidental = "n"
var/octave = "3"
var/notenum = text2ascii(note)
if(notenum < 65 || notenum > 71)
statusmsg( "Compile Error: Invalid Note Letter (A-G)\nAt Part:'[part]' Tone:'[tone]'" )
return
if(len>=2)
var/x2 = copytext(tone, 2, 3)
var/x2num = text2num(x2)
if(x2 == "b" || x2 == "n" || x2 == "#")
accidental = x2
else if(x2num >= 1 && x2num <= 9)
octave = x2
if(len==3)
statusmsg( "Compile Error: Tone Syntax Error! (incorrect order)\nAt Part:'[part]' Tone:'[tone]'" )
return
else
statusmsg( "Compile Error: Invalid Letter At Char (2)\nAt Part:'[part]' Tone:'[tone]'" )
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
if(len==3)
var/x3 = copytext(tone, 3, 4)
var/x3num = text2num(x3)
if(x3num >= 1 && x3num <= 9)
octave = x3
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
updateUsrDialog()
statusmsg( "Compile Error: Invalid Octave! (1-9)\nAt Part:'[part]' Tone:'[tone]'" )
return
//Optimize part
// Replace a flat with a sharp from the note one step darker
// If we're on the darkest note, we can't replace it by some darker (note != "C")
// C D E F G A B
if(accidental == "b" && note != "C")
accidental = "#"
if(note == "A")
note = "G"
else
note = ascii2text(text2ascii(note)-1) // Decrement by one
var/finaltone = note + accidental + octave
//Check if invalid note
if((octave == "9" && (finaltone != "Cb9" && finaltone != "Cn9")) || finaltone == "Cb1")
statusmsg( "Compile Error: Invalid Tone! (Check bottom of help for more info)\nAt Part:'[part]' Tone:'[tone]'" )
return
// TODO: OPTIMIZE SHARPS AND FLATS
//x indicates its a tone to be played
compilestring += "x" + finaltone + "¤"
//y indicates its a sleep
compilestring += "y[round((currentsong.tempo / tempodiv)*100)/100]¤"
currentsong.compiledstring = compilestring
currentsong.compilesuccess = 1
statusmsg("Compiled successfully!")
/obj/structure/device/piano/attack_hand(var/mob/user as mob)
if(!anchored)
return
usr.machine = src
var/dat = "<HEAD><TITLE>Piano</TITLE></HEAD><BODY>"
if(song)
if(song.lines.len > 0 && !(playing))
dat += "<A href='?src=\ref[src];play=1'>Play Song</A><BR><BR>"
dat += "<A href='?src=\ref[src];repeat=1'>Repeat Song: [repeat] times.</A><BR><BR>"
if(playing)
dat += "<A href='?src=\ref[src];stop=1'>Stop Playing</A><BR>"
dat += "Repeats left: [repeat].<BR><BR>"
if(!edit)
dat += "<A href='?src=\ref[src];edit=2'>Show Editor</A><BR><BR>"
/*
BPM TO TEMPO
ds = 10/(BPM/60)
TEMPO TO BPM
BPM = (10/ds)*60
*/
var/calctempo = round((10/currentsong.tempo)*60)
var/dat = {"
<html>
<head>
<title>Piano</title>
<style type="text/css">
div.content
{
background-color:#AAAAAA;
width:100%;
padding:10;
margin:5;
}
table.noborders {
border-width: 0px;
border-spacing: 0px;
border-style: none;
border-collapse: collapse;
}
table.noborders th {
border-width: 0px;
padding: 0px;
border-style: inset;
}
table.noborders td {
border-width: 0px;
padding: 0px;
border-style: inset;
}
</style>
</head>
<body>
<center><h1>[src.name == "space piano" ? "Space Piano" : "Space Minimoog"]</h1></center>
<table class="noborders" width="100%"><tr>
<td>
<div bgcolor="#AAAAAA" class="content" style="height:100%;">"}
if(showcontrol)
dat += {" <a href='?src=\ref[src];controltoggle=1'>Hide Controlpanel</a><br>"}
else
dat += "<A href='?src=\ref[src];edit=1'>Hide Editor</A><BR>"
dat += "<A href='?src=\ref[src];newsong=1'>Start a New Song</A><BR>"
dat += "<A href='?src=\ref[src];import=1'>Import a Song</A><BR><BR>"
if(song)
var/calctempo = (10/song.tempo)*60
dat += "Tempo : <A href='?src=\ref[src];tempo=10'>-</A><A href='?src=\ref[src];tempo=1'>-</A> [calctempo] BPM <A href='?src=\ref[src];tempo=-1'>+</A><A href='?src=\ref[src];tempo=-10'>+</A><BR><BR>"
var/linecount = 0
for(var/line in song.lines)
linecount += 1
dat += "Line [linecount]: [line] <A href='?src=\ref[src];deleteline=[linecount]'>Delete Line</A> <A href='?src=\ref[src];modifyline=[linecount]'>Modify Line</A><BR>"
dat += "<A href='?src=\ref[src];newline=1'>Add Line</A><BR><BR>"
if(help)
dat += "<A href='?src=\ref[src];help=1'>Hide Help</A><BR>"
dat += {"
Lines are a series of chords, separated by commas (,), each with notes seperated by hyphens (-).<br>
Every note in a chord will play together, with chord timed by the tempo.<br>
<br>
Notes are played by the names of the note, and optionally, the accidental, and/or the octave number.<br>
By default, every note is natural and in octave 3. Defining otherwise is remembered for each note.<br>
Example: <i>C,D,E,F,G,A,B</i> will play a C major scale.<br>
After a note has an accidental placed, it will be remembered: <i>C,C4,C,C3</i> is C3,C4,C4,C3</i><br>
Chords can be played simply by seperating each note with a hyphon: <i>A-C#,Cn-E,E-G#,Gn-B</i><br>
A pause may be denoted by an empty chord: <i>C,E,,C,G</i><br>
To make a chord be a different time, end it with /x, where the chord length will be length<br>
defined by tempo / x: <i>C,G/2,E/4</i><br>
Combined, an example is: <i>E-E4/4,/2,G#/8,B/8,E3-E4/4</i>
<br>
Lines may be up to 50 characters.<br>
A song may only contain up to 50 lines.<br>
"}
else
dat += "<A href='?src=\ref[src];help=2'>Show Help</A><BR>"
dat += "</BODY></HTML>"
user << browse(dat, "window=piano;size=700x300")
dat += {" <a href='?src=\ref[src];controltoggle=1'>Show Controlpanel</a><br>"}
if(showcontrol)
dat += {"
<a href='?src=\ref[src];toggleplay=1'>[playing ? "Stop Playing" : "Play [currentsong.name]"]</a><br>
<br>
<a href='?src=\ref[src];newsong=1'>New Song</a><br>
<a href='?src=\ref[src];name=1'>Rename Song</a><br>
<a href='?src=\ref[src];savesong=1'>Save [currentsong.name]</a><br>
<br>
<a href='?src=\ref[src];repeat=1'>Repeat: [repeat]</a><br>
<div style="width:auto; height:auto; background-color:#888888;" bgcolor="#888888">
<pre>Status:<br>[status]</pre>
</div>"}
dat+={"
</div>
</td>
<td width="150px">
<div bgcolor="#AAAAAA" class="content" style="width:150px; height:100%; margin-left:0;">
"}
if(showcontrol)
for(var/datum/song/isong in internalsongs)
dat += "<a href='?src=\ref[src];setsong=[isong.id]'>[isong.name]</a><br>"
dat += {"
</div>
</td>
</tr></table>
<div bgcolor="#AAAAAA" class="content" style="margin-top:0;">"}
if(showeditor)
dat += {"<a href='?src=\ref[src];editortoggle=1'>Hide Editor</a><br>"}
else
dat += {"<a href='?src=\ref[src];editortoggle=1'>Show Editor</a><br>"}
if(showeditor)
dat += {"
Tempo:
<a href='?src=\ref[src];tempo=-3'>-</a><a href='?src=\ref[src];tempo=-2'>-</a><a href='?src=\ref[src];tempo=-1'>-</a>
[calctempo] BPM
<a href='?src=\ref[src];tempo=1'>+</a><a href='?src=\ref[src];tempo=2'>+</a><a href='?src=\ref[src];tempo=3'>+</a><br>
<a href='?src=\ref[src];compile=1'>Compile</a>
<a href='?src=\ref[src];edit=1'>Edit</a>
<div bgcolor="#888888" style="padding-left:5px; margin-top:5px; background-color:#888888"><pre>[currentsong.sourcestring]</pre></div>"}
dat+={"
</div>
<div bgcolor="#AAAAAA" class="content">"}
if(showhelp)
dat += {"<a href='?src=\ref[src];helptoggle=1'>Hide Help</a><br>"}
else
dat += {"<a href='?src=\ref[src];helptoggle=1'>Show Help</a><br>"}
if(showhelp)
dat += {"
Songs are a series of chords, separated by commas (,), each with notes seperated by hyphens (-).<br>
Every note in a chord will play together, with chord timed by the tempo.<br>
<br>
Notes are played by the names of the note, and optionally, the accidental, and/or the octave number.<br>
By default, every note is natural and in octave 3. Defining otherwise is remembered for each note.<br>
Octave can be a number between 1 and 9<br>
Example: <i>C,D,E,F,G,A,B</i> will play a C major scale.<br>
After a note has an accidental placed, it will be remembered: <i>C#,C4,Cb,C3</i> is <i>C#3,Cn4,Cb3,Cn3</i><br>
Chords can be played simply by seperating each note with a hyphon: <i>A-C#,Cn-E,E-G#-Gn-B</i><br>
A pause may be denoted by an empty chord: <i>C,E,,C,G</i><br>
To make a chord be a different time, end it with /x, where the chord length will be length<br>
defined by 'tempo / x': <i>C,G/2,E/4</i><br>
Combined, an example is: <i>E-Eb4/4,/2,G#/8,B/8,E3-E4/4</i><br>
<br>
A song may only contain up to 4000 letters.<br>
If you're playing a small piece over and over, remember to put a pause at the end for it to sound properly.<br<
<br>
Note: Due to limitations in the engine, some tones doesn't exist. These are:<br>
Cb1<br>
All tones in the ninth octave <b>except Cb9 and Cn9</b>
"}
dat+={"
</div>
</body>
</html>"}
user << browse(dat, "window=piano;size=700x500")
onclose(user, "piano")
/obj/structure/device/piano/Topic(href, href_list)
@@ -310,98 +519,113 @@
onclose(usr, "piano")
return
if(href_list["newsong"])
song = new()
else if(song)
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.
var/tempnum = input("How many times do you want to repeat this piece? (max:10)") as num|null
if(tempnum > 10)
tempnum = 10
if(tempnum < 0)
tempnum = 0
repeat = round(tempnum)
if(href_list["toggleplay"])
if(playing)
playing = 0
else
playing = 1
spawn() playsong()
updateUsrDialog()
else if(href_list["controltoggle"])
showcontrol = 1-showcontrol
updateUsrDialog()
else if(href_list["editortoggle"])
showeditor = 1-showeditor
updateUsrDialog()
else if(href_list["helptoggle"])
showhelp = 1-showhelp
updateUsrDialog()
else if(href_list["name"])
var/input = html_encode(input(usr, "", "Rename", currentsong.name) as text|null)
currentsong.name = copytext(input,1,30)
updateUsrDialog()
else if(href_list["savesong"])
//Check if the song already exists in the internal
var/foundsong = 0
for(var/datum/song/isong in internalsongs)
if(isong.id == currentsong.id)
foundsong = 1
isong.compiledstring = currentsong.compiledstring
isong.sourcestring = currentsong.sourcestring
isong.name = currentsong.name
break
//If not, add it as new
if(!foundsong)
internalsongs += currentsong
updateUsrDialog()
if(playing)
if(href_list["newsong"]||href_list["setsong"]||href_list["tempo"]||href_list["compile"]||href_list["edit"]||href_list["repeat"])
statusmsg("Playback Error: Stop the song first!")
else
if(href_list["newsong"])
var/answer = alert(usr, "This will overwrite any current song you're editing!", "Are you sure?", "Yes", "No")
if(answer == "No")
return
currentsong = new()
updateUsrDialog()
else if(href_list["setsong"])
var/matchid = text2num(href_list["setsong"])
for(var/datum/song/isong in internalsongs)
if(isong.id == matchid)
currentsong = isong
break
updateUsrDialog()
else if(href_list["tempo"])
song.tempo += round(text2num(href_list["tempo"]))
if(song.tempo < 1)
song.tempo = 1
var/tempoinc = text2num(href_list["tempo"])
else if(href_list["play"])
if(song)
playing = 1
spawn() playsong()
currentsong.tempo += tempoinc*-1
if(currentsong.tempo<1)
currentsong.tempo = 1
currentsong.compilesuccess = 0
else if(href_list["newline"])
var/newline = html_encode(input("Enter your line: ", "Piano") as text|null)
if(!newline)
return
if(song.lines.len > 50)
return
if(lentext(newline) > 50)
newline = copytext(newline, 1, 50)
song.lines.Add(newline)
updateUsrDialog()
else if(href_list["deleteline"])
var/num = round(text2num(href_list["deleteline"]))
if(num > song.lines.len || num < 1)
return
song.lines.Cut(num, num+1)
else if(href_list["compile"])
else if(href_list["modifyline"])
var/num = round(text2num(href_list["modifyline"]),1)
var/content = html_encode(input("Enter your line: ", "Piano", song.lines[num]) as text|null)
if(!content)
return
if(lentext(content) > 50)
content = copytext(content, 1, 50)
if(num > song.lines.len || num < 1)
return
song.lines[num] = content
compilesong()
else if(href_list["stop"])
playing = 0
else if(href_list["help"])
help = text2num(href_list["help"]) - 1
updateUsrDialog()
else if(href_list["edit"])
edit = text2num(href_list["edit"]) - 1
else if(href_list["import"])
var/t = ""
do
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", src.name), t) as message)
if (!in_range(src, usr))
return
var/input = html_encode(input(usr, "", "Edit", currentsong.sourcestring) as message|null)
if(lentext(t) >= 3072)
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(lentext(t) > 3072)
input = dd_replacetext(input, " ", "")
input = dd_replacetext(input, "\t", "")
//split into lines
spawn()
var/list/lines = dd_text2list(t, "\n")
var/tempo = 5
if(copytext(lines[1],1,6) == "BPM: ")
tempo = 600 / text2num(copytext(lines[1],6))
lines.Cut(1,2)
if(lines.len > 50)
usr << "Too many lines!"
lines.Cut(51)
var/linenum = 1
for(var/l in lines)
if(lentext(l) > 50)
usr << "Line [linenum] too long!"
lines.Remove(l)
else
linenum++
song = new()
song.lines = lines
song.tempo = tempo
updateUsrDialog()
if(lentext(input)>4000)
statusmsg("Editor Error: Song too long, end was cutoff (max 4000)")
input = copytext(input, 1, 4001)
currentsong.sourcestring = input
currentsong.compilesuccess = 0
updateUsrDialog()
else if(href_list["repeat"])
var/input = round(input(usr, "", "Repeat", "How many times do you want to repeat? (max 10)") as num|null)
if(input < 1)
input = 1
else if(input > 10)
input = 10
repeat = input
add_fingerprint(usr)
updateUsrDialog()