Initial commit of media suite

Conflicts:
	baystation12.dme
	code/controllers/configuration.dm
	code/game/area/areas.dm
	code/modules/client/client defines.dm
This commit is contained in:
Rob Nelson
2014-03-10 08:38:03 -07:00
committed by ZomgPonies
parent a9f67bf557
commit 8fb14a26e9
86 changed files with 36028 additions and 34 deletions
+4
View File
@@ -0,0 +1,4 @@
// Called when a mob moves from one MASTER area to another.
// (Master, as opposed to lighting subareas)
/hook/mobAreaChange
name = "MobAreaChange"
+54
View File
@@ -0,0 +1,54 @@
/************
* D2K5-STYLE HOOKS
*
* BLATANTLY STOLEN FROM D2K5 AND MODIFIED
*
* SOMEHOW SUCKS LESS THAN BAY'S HOOKS
************
The major change is to standardize them a bit
by changing the event prefix to On instead of Hook.
Oh and it's documented and cleaned up. - N3X
*/
/hook
var/name = "DefaultHookName"
var/list/handlers = list()
proc/Called(var/list/args) // When the hook is called
return 0
proc/Setup() // Called when the setup things is ran for the hook, objs contain all objects with that is hooking
/hook_handler
// Your hook handler should do this:
// proc/OnThingHappened(var/list/args)
// return handled // boolean
var/global/list/hooks = list()
/proc/SetupHooks()
for (var/hook_path in typesof(/hook))
var/hook/hook = new hook_path
hooks[hook.name] = hook
//world.log << "Found hook: " + hook.name
for (var/hook_path in typesof(/hook_handler))
var/hook_handler/hook_handler = new hook_path
for (var/name in hooks)
if (hascall(hook_handler, "On" + name))
var/hook/hook = hooks[name]
hook.handlers += hook_handler
//world.log << "Found hook handler for: " + name
for (var/hook/hook in hooks)
hook.Setup()
/proc/CallHook(var/name as text, var/list/args)
var/hook/hook = hooks[name]
if (!hook)
//world.log << "WARNING: Hook with name " + name + " does not exist"
return
if (hook.Called(args))
return
for (var/hook_handler/hook_handler in hook.handlers)
call(hook_handler, "On" + hook.name)(args)
+6
View File
@@ -72,6 +72,8 @@
var/wikiurl = "http://baystation12.net/wiki/index.php?title=Main_Page"
var/forumurl = "http://baystation12.net/forums/"
var/media_base_url = "http://80.244.78.90/media" // http://ss13.nexisonline.net/media
//Alert level description
var/alert_desc_green = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced."
var/alert_desc_blue_upto = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted."
@@ -450,6 +452,10 @@
if("assistant_ratio")
config.assistantratio = text2num(value)
if("media_base_url")
media_base_url = value
else
diary << "Unknown setting in configuration: '[name]'"
+36 -30
View File
@@ -323,46 +323,52 @@
if(!L.lastarea)
L.lastarea = get_area(L.loc)
if(L.lastarea.master)
L.lastarea = L.lastarea.master
var/area/newarea = get_area(L.loc)
if(newarea.master)
newarea = newarea.master
var/area/oldarea = L.lastarea
if((oldarea.has_gravity == 0) && (newarea.has_gravity == 1) && (L.m_intent == "run")) // Being ready when you change areas gives you a chance to avoid falling all together.
thunk(L)
L.lastarea = newarea
// /vg/ - EVENTS!
CallHook("MobAreaChange", list("mob" = L, "new" = newarea, "old" = oldarea))
// Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
if(!(L && L.client && (L.client.prefs.sound & SOUND_AMBIENCE))) return
if(L && L.client && (L.client.prefs.toggles & SOUND_AMBIENCE))
if(!L.client.ambience_playing)
L.client.ambience_playing = 1
L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = 2)
if(!L.client.ambience_playing)
L.client.ambience_playing = 1
L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = 2)
if(prob(35) && !newarea.media_source)
// TODO: This is dumb. - N3X
if(istype(src, /area/chapel))
sound = pick('sound/ambience/ambicha1.ogg','sound/ambience/ambicha2.ogg','sound/ambience/ambicha3.ogg','sound/ambience/ambicha4.ogg','sound/music/traitor.ogg')
else if(istype(src, /area/medical/morgue))
sound = pick('sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg','sound/music/main.ogg')
else if(type == /area)
sound = pick('sound/ambience/ambispace.ogg','sound/music/title2.ogg','sound/music/space.ogg','sound/music/main.ogg','sound/music/traitor.ogg')
else if(istype(src, /area/engine))
sound = pick('sound/ambience/ambisin1.ogg','sound/ambience/ambisin2.ogg','sound/ambience/ambisin3.ogg','sound/ambience/ambisin4.ogg')
else if(istype(src, /area/AIsattele) || istype(src, /area/turret_protected/ai) || istype(src, /area/turret_protected/ai_upload) || istype(src, /area/turret_protected/ai_upload_foyer))
sound = pick('sound/ambience/ambimalf.ogg')
else if(istype(src, /area/mine/explored) || istype(src, /area/mine/unexplored))
sound = pick('sound/ambience/ambimine.ogg', 'sound/ambience/song_game.ogg')
musVolume = 25
else if(istype(src, /area/tcommsat) || istype(src, /area/turret_protected/tcomwest) || istype(src, /area/turret_protected/tcomeast) || istype(src, /area/turret_protected/tcomfoyer) || istype(src, /area/turret_protected/tcomsat))
sound = pick('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
else
sound = pick('sound/ambience/ambigen1.ogg','sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg','sound/ambience/ambigen14.ogg')
if(prob(35))
if(istype(src, /area/chapel))
sound = pick('sound/ambience/ambicha1.ogg','sound/ambience/ambicha2.ogg','sound/ambience/ambicha3.ogg','sound/ambience/ambicha4.ogg','sound/music/traitor.ogg')
else if(istype(src, /area/medical/morgue))
sound = pick('sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg','sound/music/main.ogg')
else if(type == /area)
sound = pick('sound/ambience/ambispace.ogg','sound/music/title2.ogg','sound/music/space.ogg','sound/music/main.ogg','sound/music/traitor.ogg')
else if(istype(src, /area/engine))
sound = pick('sound/ambience/ambisin1.ogg','sound/ambience/ambisin2.ogg','sound/ambience/ambisin3.ogg','sound/ambience/ambisin4.ogg')
else if(istype(src, /area/AIsattele) || istype(src, /area/turret_protected/ai) || istype(src, /area/turret_protected/ai_upload) || istype(src, /area/turret_protected/ai_upload_foyer))
sound = pick('sound/ambience/ambimalf.ogg')
else if(istype(src, /area/mine/explored) || istype(src, /area/mine/unexplored))
sound = pick('sound/ambience/ambimine.ogg', 'sound/ambience/song_game.ogg')
musVolume = 25
else if(istype(src, /area/tcommsat) || istype(src, /area/turret_protected/tcomwest) || istype(src, /area/turret_protected/tcomeast) || istype(src, /area/turret_protected/tcomfoyer) || istype(src, /area/turret_protected/tcomsat))
sound = pick('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
else
sound = pick('sound/ambience/ambigen1.ogg','sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg','sound/ambience/ambigen14.ogg')
if(!L.client.played)
L << sound(sound, repeat = 0, wait = 0, volume = musVolume, channel = 1)
L.client.played = 1
spawn(600) //ewww - this is very very bad
if(L.&& L.client)
L.client.played = 0
if(!L.client.played)
L << sound(sound, repeat = 0, wait = 0, volume = musVolume, channel = 1)
L.client.played = 1
spawn(600) //ewww - this is very very bad
if(L.&& L.client)
L.client.played = 0
/area/proc/gravitychange(var/gravitystate = 0, var/area/A)
+7 -2
View File
@@ -40,8 +40,13 @@
var/related_accounts_ip = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this ip
var/related_accounts_cid = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this computer id
preload_rsc = 0 // This is 0 so we can set it to an URL once the player logs in and have them download the resources from a different server.
preload_rsc = 1 // This is 0 so we can set it to an URL once the player logs in and have them download the resources from a different server.
var/karma = 0
var/karma_spent = 0
var/karma_spent = 0
/////////////////////////////////////////////
// /vg/: MEDIAAAAAAAA
// Set on login.
var/datum/media_manager/media = null
+131
View File
@@ -0,0 +1,131 @@
/*******************************
* Largely a rewrite of the Jukebox from D2K5
*
* By N3X15
*******************************/
#define JUKEMODE_SHUFFLE 1 // Default
#define JUKEMODE_REPEAT_SONG 2
#define JUKEMODE_PLAY_ONCE 3 // Play, then stop.
#define JUKEMODE_COUNT 3
// Represents a record returned.
/datum/song_info
var/title = ""
var/artist = ""
var/album = ""
var/url = ""
var/length = 0 // decaseconds
New(var/list/json)
title = json["title"]
artist = json["artist"]
album = json["album"]
url = json["url"]
length = text2num(json["length"])
var/global/loopModeNames=list(
JUKEMODE_SHUFFLE = "Shuffle",
JUKEMODE_REPEAT_SONG = "Single",
JUKEMODE_PLAY_ONCE= "Once",
)
/obj/machinery/media/jukebox
name = "Jukebox"
desc = "A jukebox used for parties and shit."
icon = 'icons/obj/jukebox.dmi'
icon_state = "jukebox"
density = 1
anchored = 1
luminosity = 4 // Why was this 16
var/loop_mode = JUKEMODE_SHUFFLE
// /datum/song_info
var/list/playlist
var/current_song=0
/obj/machinery/media/jukebox/attack_ai()
return
/obj/machinery/media/jukebox/attack_paw()
return
/obj/machinery/media/jukebox/attack_hand(var/mob/user)
var/t = "<h1>Jukebox Interface</h1>"
t += "<b>Power:</b> <a href='?src=\ref[src];power=1'>[playing?"On":"Off"]</a><br />"
t += "<b>Play Mode:</b> <a href='?src=\ref[src];loop=1'>[loopModeNames[loop_mode]]</a><br />"
if(current_song)
var/datum/song_info/song=playlist[current_song]
t += "<b>Current song:</b> [song.artist] - [song.title]<br />"
t += "<table class='prettytable'><tr><th colspan='2'>Artist - Title</th><th>Album</th></tr>"
var/i
for(i = 1,i <= playlist.len,i++)
var/datum/song_info/song=playlist[i]
t += "<tr><th>#[i]</th><td><A href='?src=\ref[src];song=[i]'>[song.artist] - [song.title]</A></td><td>[song.album]</td></tr>"
t += "</table>"
user.set_machine(src)
var/datum/browser/popup = new (user,"jukebox",name,420,700)
popup.set_content(t)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/media/jukebox/Topic(href, href_list)
..()
if (href_list["power"])
playing=!playing
if (href_list["song"])
current_song=Clamp(text2num(href_list["song"]),1,playlist.len)
update_music()
if (href_list["mode"])
// Theoretically, this should barrel shift.
loop_mode = (loop_mode % JUKEMODE_COUNT)+1
return attack_hand(usr)
/obj/machinery/media/jukebox/process()
if(!playlist)
var/url="[config.media_base_url]/index.php"
var/response = world.Export(url)
playlist=list()
if(response)
var/json = file2text(response["CONTENT"])
var/json_reader/reader = new()
reader.tokens = reader.ScanJson(json)
reader.i = 1
var/songdata = reader.read_value()
for(var/list/record in songdata)
playlist += new /datum/song_info(record)
else
stat &= BROKEN
update_icon()
return
if(playing)
var/datum/song_info/song
if(current_song)
song = playlist[current_song]
if(!current_song || (song && world.time >= media_start_time + song.length))
current_song=1
switch(loop_mode)
if(JUKEMODE_SHUFFLE)
current_song=rand(1,playlist.len)
if(JUKEMODE_REPEAT_SONG)
current_song=current_song
if(JUKEMODE_PLAY_ONCE)
playing=0
return
if(!playing) return
update_music()
/obj/machinery/media/jukebox/update_music()
var/datum/song_info/song = playlist[current_song]
media_url = song.url
media_start_time = world.time
visible_message("<span class='notice'>\icon[src] \The [src] begins to play \"[song.title]\", by [song.artist].</notice>","<em>You hear music.</em>")
visible_message("<span class='notice'>\icon[src] \The [src] warbles: [song.length]ds, [song.url]</notice>")
..()
+15
View File
@@ -0,0 +1,15 @@
// Machinery serving as a media source.
/obj/machinery/media
var/playing=0
var/media_url=""
var/media_start_time=0
// Notify everyone in the area of new music.
// YOU MUST SET MEDIA_URL AND MEDIA_START_TIME YOURSELF!
/obj/machinery/media/proc/update_music()
var/area/A = get_area(src)
if(A.master)
A=A.master
for(var/mob/M in A)
if(M && M.client)
M.update_music()
+84
View File
@@ -0,0 +1,84 @@
/**********************
* AWW SHIT IT'S TIME FOR RADIO
*
* Concept stolen from D2K5
*
* Rewritten (except for player HTML) by N3X15
***********************/
// Open up WMP and play musique.
// TODO: Convert to VLC for cross-platform and ogg support. - N3X
var/const/PLAYER_HTML={"
<OBJECT id='player' CLASSID='CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6' type='application/x-oleobject'></OBJECT>
<script>
function noErrorMessages () { return true; }
window.onerror = noErrorMessages;
function SetMusic(url, time, volume) {
var player = document.getElementById('player');
player.URL = url;
player.Controls.currentPosition = time;
player.Settings.volume = volume;
}
</script>"}
// Hook into the events we desire.
/hook_handler/soundmanager
// Set up player on login
proc/OnLogin(var/list/args)
var/client/C = args["client"]
C.media = new /datum/media_manager(C)
C.media.open()
// Update when moving between areas.
proc/OnMobAreaChange(var/list/args)
var/mob/M = args["mob"]
M.update_music()
/mob/proc/update_music()
if (client)
if(client.media)
client.media.update_music()
/area
// One media source per area.
var/obj/machinery/media/media_source = null
/datum/media_manager
var/url = ""
var/start_time = 0
var/volume = 100
var/client/owner
New(var/mob/holder)
src.owner=holder
// Actually pop open the player in the background.
proc/open()
owner << browse(PLAYER_HTML, "window=rpane.hosttracker")
send_update()
// Tell the player to play something via JS.
proc/send_update()
owner << output(list2params(list(url, (world.timeofday - start_time) / 10, volume)), "rpane.hosttracker:SetMusic")
// Scan for media sources and use them.
proc/update_music()
var/targetURL = ""
var/targetStartTime = 0
var/targetVolume = 100
if (owner)
var/area/A = get_area()
var/obj/machinery/media/M = A.media_source
if(M.playing)
targetURL = M.media_url
targetStartTime = M.media_start_time
if (url != targetURL || abs(targetStartTime - start_time) > 1 || targetVolume != volume)
url = targetURL
start_time = targetStartTime
volume = targetVolume
send_update()
+3 -1
View File
@@ -54,4 +54,6 @@
if(istype(src,/mob/living/carbon/human))
var/mob/living/carbon/human/H = src
if(H.species && H.species.abilities)
client.verbs |= H.species.abilities
client.verbs |= H.species.abilities
CallHook("Login", list("client" = src.client, "mob" = src))
+2
View File
@@ -59,11 +59,13 @@ json_reader
while(++i <= lentext(json))
var/char = get_char()
if(escape)
escape=FALSE // WHICH STUPID ASSHOLE FORGOT THIS - N3X
switch(char)
if("\\", "'", "\"", "/", "u")
val += char
else
// TODO: support octal, hex, unicode sequences
//testing("Having trouble with \"\\[char]\" in string \"[val]\"")
ASSERT(sequences.Find(char))
val += ascii2text(sequences[char])
else