This commit is contained in:
I_VAPE_VOX_CLOACA_EVERY_DAY_OF_MY_LIFE
2019-01-25 22:54:00 -03:00
parent b6235d6c86
commit 0168697f21
16 changed files with 462 additions and 113 deletions

View File

@@ -113,7 +113,9 @@ CREATE TABLE client (
parallax_speed INTEGER,
stumble INTEGER,
attack_animation INTEGER,
pulltoggle INTEGER
pulltoggle INTEGER,
credits TEXT,
jingle TEXT
);

View File

@@ -1539,6 +1539,13 @@ var/proccalls = 1
#define ITEM_ANIMATION 1
#define PERSON_ANIMATION 2
//For client preferences.
#define CREDITS_NEVER "Never"
#define CREDITS_ALWAYS "Always"
#define CREDITS_NO_RERUNS "No Reruns"
#define JINGLE_NEVER "Never"
#define JINGLE_CLASSIC "Classics"
#define JINGLE_ALL "All"
#define GOLEM_RESPAWN_TIME 10 MINUTES //how much time must pass before someone who dies as an adamantine golem can use the golem rune again

View File

@@ -436,7 +436,10 @@ var/datum/controller/gameticker/ticker
spawn
declare_completion()
end_credits.on_roundend()
end_credits.on_round_end()
gameend_time = world.time / 10
if(config.map_voting)
//testing("Vote picked [chosen_map]")
vote.initiate_vote("map","The Server", popup = 1, weighted_vote = config.weighted_votes)

View File

@@ -1507,14 +1507,21 @@ proc/formatPlayerPanel(var/mob/U,var/text="PP")
return
var/dat = "<center><B>Credits Panel</B></center><hr>"
dat += "<center><B>Star Of The Show:</b></center>"
dat += "Chosen Star: [isnull(end_credits.star) ? "(Will Select Automatically)" : end_credits.star] <A href='?src=\ref[src];credits=setstartext'>(Set Plaintext)</A> <A href='?src=\ref[src];credits=setstarmob'>(Set Mob From List)</A> "
if(!isnull(end_credits.star) && !end_credits.drafted)
dat += "<A href='?src=\ref[src];credits=resetstar'>(Reset)</A> "
if(!end_credits.drafted)
dat += "<span style='color:red'><br>The round isn't over, so the featured star hasn't been picked yet.<br>You can manually set one now, or whichever human has talked the most this round will automatically be selected as the featured star when the round ends.</span>"
dat += "<hr>"
dat += "<center><B>Episode Name:</B></center>"
dat += "Chosen Name: [end_credits.episode_name == "" ? "(Will Generate Automatically)" : end_credits.episode_name] <A href='?src=\ref[src];credits=setname'>(Set) </A>"
if(end_credits.episode_name != "" && !end_credits.generated)
dat += "<A href='?src=\ref[src];credits=resetname'>(Reset)</A>"
else if(end_credits.generated)
dat += "<A href='?src=\ref[src];credits=rerollname'>(Reroll!)</A>"
dat += "Chosen Name: [end_credits.episode_name == "" ? "(Will Generate Automatically)" : end_credits.episode_name] <A href='?src=\ref[src];credits=setname'>(Set)</A> "
if(end_credits.episode_name != "" && !end_credits.drafted)
dat += "<A href='?src=\ref[src];credits=resetname'>(Reset)</A> "
else if(end_credits.drafted)
dat += "<A href='?src=\ref[src];credits=rerollname'>(Reroll!)</A> "
dat += "<br>"
if(!end_credits.generated)
if(!end_credits.drafted)
dat += "<span style='color:red'>The round isn't over, so the name possibilities haven't been drafted yet.<br>You can manually write down a set name now, or come back when the round ends.</span>"
else
dat += "Drafted Name Possibilities: "
@@ -1524,7 +1531,7 @@ proc/formatPlayerPanel(var/mob/U,var/text="PP")
dat += "</div>"
dat += "<hr>"
dat += "<center><B>Disclaimers:</B></center>"
if(!end_credits.generated)
if(!end_credits.drafted)
dat += "<span style='color:red'>The round isn't over, so the disclaimers haven't been generated yet.<br>You can add some now (they will show up at the top), or come back when the round ends.</span>"
dat += "<br>Generated Disclaimers: "
dat += "<div id='disclaimers'>"

View File

@@ -4834,9 +4834,28 @@
else if(href_list["credits"])
switch(href_list["credits"])
if("resetstar")
if(!end_credits.drafted) //Just in case the button somehow gets clicked when it shouldn't
end_credits.star = null
log_admin("[key_name(usr)] reset the current round's featured star. A new one will automatically generate later.")
message_admins("[key_name_admin(usr)] reset the current round's featured star. A new one will automatically generate later.")
if("setstartext")
var/newstar = thebigstar(input(usr,"Write the new star. In the final credits, it will be displayed as: 'Starring\[linebreak\]\[whatever you type here\]'. Mind your capitalization! You may also use HTML. Do not include the characters '%<splashbreak>' anywhere unless you know what you're doing, please.","in my dream, i am the star. its me",null) as text|null)
if(newstar)
end_credits.star = newstar
log_admin("[key_name(usr)] forced the current round's featured star to be '[newstar]'")
message_admins("[key_name_admin(usr)] forced the current round's featured star to be '[newstar]'")
if("setstarmob")
var/newstar = thebigstar(input(usr, "Who should be the featured star of this episode? WARNING: Only tested with humans.", "New star from moblist...") as null|anything in sortmobs())
if(newstar)
end_credits.star = newstar
log_admin("[key_name(usr)] forced the current round's featured star to be '[newstar]'")
message_admins("[key_name_admin(usr)] forced the current round's featured star to be '[newstar]'")
if("resetname")
if(!end_credits.generated) //Just in case the button somehow gets clicked when it shouldn't
if(!end_credits.drafted) //Just in case the button somehow gets clicked when it shouldn't
end_credits.episode_name = ""
end_credits.is_rerun = initial(end_credits.is_rerun)
log_admin("[key_name(usr)] reset the current round's episode name. A new one will automatically generate later.")
message_admins("[key_name_admin(usr)] reset the current round's episode name. A new one will automatically generate later.")
if("rerollname")
@@ -4846,7 +4865,8 @@
if("setname")
var/newname = input(usr,"Write the name of this latest rerun...","New Episode Name") as text|null
if(newname)
end_credits.episode_name = newname
end_credits.episode_name = uppertext(newname)
end_credits.is_rerun = FALSE
log_admin("[key_name(usr)] forced the current round's episode name to '[newname]'")
message_admins("[key_name_admin(usr)] forced the current round's episode name to '[newname]'")
@@ -4856,6 +4876,7 @@
var/newname = input(usr,"Write a new possible episode name. This is NOT guaranteed to be picked as the final name, unless you modified the weight to 99999% or something.","Edit Name",N.thename) as text|null
if(newname)
N.thename = newname
N.rare = TRUE
if("namedatumweight")
var/datum/episode_name/N = locate(href_list["nameref"])
if(N)

View File

@@ -84,5 +84,8 @@
var/list/ViewFilter = list()
var/list/ObscuredTurfs = list()
var/received_credits = FALSE
var/received_roundend_audio = FALSE
var/list/person_animation_viewers = list()
var/list/item_animation_viewers = list()

View File

@@ -199,6 +199,10 @@ var/const/MAX_SAVE_SLOTS = 8
var/progress_bars = 1 //Whether to show progress bars when doing delayed actions.
var/pulltoggle = 1 //If 1, the "pull" verb toggles between pulling/not pulling. If 0, the "pull" verb will always try to pull, and do nothing if already pulling.
var/credits = CREDITS_ALWAYS
var/jingle = JINGLE_CLASSIC
var/client/client
var/saveloaded = 0
@@ -380,6 +384,10 @@ var/const/MAX_SAVE_SLOTS = 8
<a href='?_src_=prefs;preference=special_popup'><b>[special_popup ? "Yes" : "No"]</b></a><br>
<b>Attack Animations:<b>
<a href='?_src_=prefs;preference=attack_animation'><b>[attack_animation ? (attack_animation == ITEM_ANIMATION? "Item Anim." : "Person Anim.") : "No"]</b></a><br>
<b>Show Credits <span title='&#39;No Reruns&#39; will roll credits only if an admin set a special episode name, or if a rare and exclusive episode name was selected thanks to something uncommon happening that round.'>(?):</span><b>
<a href='?_src_=prefs;preference=credits'><b>[credits]</b></a><br>
<b>Server Shutdown Jingle <span title='These jingles will only play if credits don&#39;t roll for you that round. &#39;Classics&#39; will only play &#39;APC Destroyed&#39; and &#39;Banging Donk&#39;, &#39;All&#39; will play the previous plus retro videogame sounds.'>(?):</span><b>
<a href='?_src_=prefs;preference=jingle'><b>[jingle]</b></a><br>
</div>
</div>"}
@@ -492,6 +500,9 @@ var/const/MAX_SAVE_SLOTS = 8
var/available_in_days = job.available_in_days(user.client)
HTML += "<font color=red>[rank]</font></td><td><font color=red> \[IN [(available_in_days)] DAYS]</font></td></tr>"
continue
if((job_civilian_low & ASSISTANT) && (rank != "Assistant"))
HTML += "<font color=orange>[rank]</font></td><td></td></tr>"
continue
if((rank in command_positions) || (rank == "AI"))//Bold head jobs
if(job.alt_titles)
HTML += "<b><span class='dark'><a href=\"byond://?src=\ref[user];preference=job;task=alt_title;job=\ref[job]\">[GetPlayerAltTitle(job)]</a></span></b>"
@@ -549,6 +560,14 @@ var/const/MAX_SAVE_SLOTS = 8
HTML += "<a class='white' onmouseup='javascript:return mouseUp(event,[prefUpperLevel],[prefLowerLevel], \"[rank]\");' oncontextmenu='javascript:return mouseDown(event,[prefUpperLevel],[prefLowerLevel], \"[rank]\");'>"
if(rank == "Assistant")//Assistant is special
if(job_civilian_low & ASSISTANT)
HTML += " <font color=green>Yes</font>"
else
HTML += " <font color=red>No</font>"
HTML += "</a></td></tr>"
continue
//if(job.alt_titles)
//HTML += "</a></td></tr><tr bgcolor='[lastJob.selection_color]'><td width='60%' align='center'><a>&nbsp</a></td><td><a href=\"byond://?src=\ref[user];preference=job;task=alt_title;job=\ref[job]\">\[[GetPlayerAltTitle(job)]\]</a></td></tr>"
HTML += "<font color=[prefLevelColor]>[prefLevelLabel]</font>"
@@ -715,6 +734,14 @@ var/const/MAX_SAVE_SLOTS = 8
ShowChoices(user)
return
if(role == "Assistant")
if(job_civilian_low & job.flag)
job_civilian_low &= ~job.flag
else
job_civilian_low |= job.flag
SetChoices(user)
return 1
if(job.species_blacklist.Find(src.species)) //Check if our species is in the blacklist
to_chat(user, "<span class='notice'>Your species ("+src.species+") can't have this job!</span>")
return
@@ -1440,6 +1467,24 @@ NOTE: The change will take effect AFTER any current recruiting periods."}
attack_animation = NO_ANIMATION
person_animation_viewers -= client
if("credits")
switch(credits)
if(CREDITS_NEVER)
credits = CREDITS_ALWAYS
if(CREDITS_ALWAYS)
credits = CREDITS_NO_RERUNS
if(CREDITS_NO_RERUNS)
credits = CREDITS_NEVER
if("jingle")
switch(jingle)
if(JINGLE_NEVER)
jingle = JINGLE_CLASSIC
if(JINGLE_CLASSIC)
jingle = JINGLE_ALL
if(JINGLE_ALL)
jingle = JINGLE_NEVER
if(user.client.holder)
switch(href_list["preference"])
if("hear_ahelp")

View File

@@ -98,6 +98,8 @@
stumble = text2num(preference_list_client["stumble"])
attack_animation= text2num(preference_list_client["attack_animation"])
pulltoggle = text2num(preference_list_client["pulltoggle"])
credits = preference_list_client["credits"]
jingle = preference_list_client["jingle"]
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog))
@@ -119,6 +121,8 @@
stumble = sanitize_integer(stumble, 0, 1, initial(stumble))
attack_animation= sanitize_integer(attack_animation, 0, 65535, initial(attack_animation))
pulltoggle = sanitize_integer(pulltoggle, 0, 1, initial(pulltoggle))
credits = sanitize_inlist(credits, list(CREDITS_NEVER, CREDITS_ALWAYS, CREDITS_NO_RERUNS), initial(credits))
jingle = sanitize_inlist(jingle, list(JINGLE_NEVER, JINGLE_CLASSIC, JINGLE_ALL), initial(jingle))
initialize_preferences()
return 1
@@ -168,6 +172,8 @@
S["randomslot"] >> randomslot
S["volume"] >> volume
S["special_popup"] >> special_popup
S["credits"] >> credits
S["jingle"] >> jingle
//Sanitize
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog))
@@ -180,6 +186,8 @@
randomslot = sanitize_integer(randomslot, 0, 1, initial(randomslot))
volume = sanitize_integer(volume, 0, 100, initial(volume))
special_popup = sanitize_integer(special_popup, 0, 1, initial(special_popup))
credits = sanitize_inlist(credits, list(CREDITS_NEVER, CREDITS_ALWAYS, CREDITS_NO_RERUNS), initial(credits))
jingle = sanitize_inlist(jingle, list(JINGLE_NEVER, JINGLE_CLASSIC, JINGLE_ALL), initial(jingle))
initialize_preferences()
return 1
@@ -197,15 +205,15 @@
check.Add("SELECT ckey FROM client WHERE ckey = ?", ckey)
if(check.Execute(db))
if(!check.NextRow())
q.Add("INSERT into client (ckey, ooc_color, lastchangelog, UI_style, default_slot, toggles, UI_style_color, UI_style_alpha, warns, warnbans, randomslot, volume, usewmp, special, usenanoui, tooltips, progress_bars, space_parallax, space_dust, parallax_speed, stumble, attack_animation, pulltoggle) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",\
ckey, ooccolor, lastchangelog, UI_style, default_slot, toggles, UI_style_color, UI_style_alpha, warns, warnbans, randomslot, volume, usewmp, special_popup, usenanoui, tooltips, progress_bars, space_parallax, space_dust, parallax_speed, stumble, attack_animation, pulltoggle)
q.Add("INSERT into client (ckey, ooc_color, lastchangelog, UI_style, default_slot, toggles, UI_style_color, UI_style_alpha, warns, warnbans, randomslot, volume, usewmp, special, usenanoui, tooltips, progress_bars, space_parallax, space_dust, parallax_speed, stumble, attack_animation, pulltoggle, credits, jingle) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",\
ckey, ooccolor, lastchangelog, UI_style, default_slot, toggles, UI_style_color, UI_style_alpha, warns, warnbans, randomslot, volume, usewmp, special_popup, usenanoui, tooltips, progress_bars, space_parallax, space_dust, parallax_speed, stumble, attack_animation, pulltoggle, credits, jingle)
if(!q.Execute(db))
message_admins("Error #: [q.Error()] - [q.ErrorMsg()]")
WARNING("Error #:[q.Error()] - [q.ErrorMsg()]")
return 0
else
q.Add("UPDATE client SET ooc_color=?,lastchangelog=?,UI_style=?,default_slot=?,toggles=?,UI_style_color=?,UI_style_alpha=?,warns=?,warnbans=?,randomslot=?,volume=?,usewmp=?,special=?,usenanoui=?,tooltips=?,progress_bars=?,space_parallax=?,space_dust=?,parallax_speed=?, stumble=?, attack_animation=?, pulltoggle=? WHERE ckey = ?",\
ooccolor, lastchangelog, UI_style, default_slot, toggles, UI_style_color, UI_style_alpha, warns, warnbans, randomslot, volume, usewmp, special_popup, usenanoui, tooltips, progress_bars, space_parallax, space_dust, parallax_speed, stumble, attack_animation, pulltoggle, ckey)
q.Add("UPDATE client SET ooc_color=?,lastchangelog=?,UI_style=?,default_slot=?,toggles=?,UI_style_color=?,UI_style_alpha=?,warns=?,warnbans=?,randomslot=?,volume=?,usewmp=?,special=?,usenanoui=?,tooltips=?,progress_bars=?,space_parallax=?,space_dust=?,parallax_speed=?, stumble=?, attack_animation=?, pulltoggle=?, credits=?, jingle=? WHERE ckey = ?",\
ooccolor, lastchangelog, UI_style, default_slot, toggles, UI_style_color, UI_style_alpha, warns, warnbans, randomslot, volume, usewmp, special_popup, usenanoui, tooltips, progress_bars, space_parallax, space_dust, parallax_speed, stumble, attack_animation, pulltoggle, credits, jingle, ckey)
if(!q.Execute(db))
message_admins("Error #: [q.Error()] - [q.ErrorMsg()]")
WARNING("Error #:[q.Error()] - [q.ErrorMsg()]")
@@ -245,6 +253,9 @@
S["space_dust"] << space_dust
S["parallax_speed"] << parallax_speed
S["attack_animation"]<< attack_animation
S["pulltoggle"] << pulltoggle
S["credits"] << credits
S["jingle"] << jingle
return 1
//saving volume changes

View File

@@ -1,97 +1,183 @@
var/global/datum/credits/end_credits = new
/datum/credits
var/generated = FALSE
var/starting_delay = 10 SECONDS
var/post_delay = 5 SECONDS //time that the server stays up after the credits start rolling (to prevent serb shutting down before all the clients receive the credits, or that's the idea at least)
var/audio_post_delay = 10 SECONDS //Audio will start playing this many seconds before server shutdown.
var/scroll_speed = 20 //Lower is faster.
var/splash_time = 2000 //Time in miliseconds that each head of staff/star/production staff etc splash screen gets before displaying the next one.
var/song_link = "http://ss13.moe:3000/Pomf/vgstation-media/raw/master/shuttle/Frolic%20-%20Luciano%20Michelini.mp3"
var/control = "mapwindow.credits"
var/control = "mapwindow.credits" //if updating this, update in credits.html as well
var/file = 'code/modules/credits/credits.html'
var/director = "Pomf Chicken Productions"
var/list/producers = list()
var/mob/living/carbon/human/star
var/mob/living/carbon/human/most_talked //Human that talked the most this round. Will become the star if admins don't set one.
var/star //Is text returned by thebigstar(), not a mob.
var/list/disclaimers = list()
var/list/datum/episode_name/episode_names = list()
var/episode_name = ""
var/is_rerun = TRUE //A 'rerun' is defined as a round where no admin set a custom episode name and the rolled episode name wasn't of the /rare subtype.
var/producers_string = ""
var/episode_string = ""
var/cast_string = ""
var/disclaimers_string = ""
var/star_string = ""
/datum/credits/proc/on_roundend()
generate_caststring() //roundend grief not included in the credits
generate_producerstring() //so that we show admins who have logged out before the credits roll
var/drafted = FALSE
var/finalized = FALSE
var/js_args = list()
var/audio_link = "http://ss13.moe/media/source/roundend/credits/Frolic_Luciano_Michelini.mp3"
var/list/classic_roundend_jingles = list(
"http://ss13.moe/media/source/roundend/jingleclassic/bangindonk.mp3",
"http://ss13.moe/media/source/roundend/jingleclassic/apcdestroyed.mp3"
)
var/list/new_roundend_jingles = list(
"http://ss13.moe/media/source/roundend/jinglenew/FTLvictory.mp3",
"http://ss13.moe/media/source/roundend/jinglenew/bayojingle.mp3",
"http://ss13.moe/media/source/roundend/jinglenew/calamitytrigger.mp3",
"http://ss13.moe/media/source/roundend/jinglenew/castlevania.mp3",
"http://ss13.moe/media/source/roundend/jinglenew/duckgame.mp3",
"http://ss13.moe/media/source/roundend/jinglenew/gameoveryeah.mp3",
"http://ss13.moe/media/source/roundend/jinglenew/marioworld.mp3",
"http://ss13.moe/media/source/roundend/jinglenew/megamanX.mp3",
"http://ss13.moe/media/source/roundend/jinglenew/rayman.mp3",
"http://ss13.moe/media/source/roundend/jinglenew/slugmissioncomplete.mp3",
"http://ss13.moe/media/source/roundend/jinglenew/soniclevelcomplete.mp3",
"http://ss13.moe/media/source/roundend/jinglenew/tfvictory.mp3"
)
/*
* draft():
* Stage 1 of credit assembly. Called as soon as the rock cooks. Picks the episode names, staff, etc.
* and allows the admins to edit those before the round ends proper and the credits roll.
* Called by on_round_end() (on normal roundend, otherwise on_world_reboot_start() will call finalize() which will call us)
*/
/datum/credits/proc/draft(var/force = FALSE)
if(drafted && !force)
return
draft_caststring() //roundend grief not included in the credits
draft_producerstring() //so that we show admins who have logged out before the credits roll
draft_star() //done early so admins have time to edit it
draft_disclaimers()
draft_episode_names() //only selects the possibilities, doesn't pick one yet
generated = TRUE
drafted = TRUE
/datum/credits/proc/rollem()
/*
* finalize():
* Stage 2 of credit assembly. Called shortly before the server shuts down.
* Takes all of our drafted, possibly admin-edited stuff, packages it up into JS arguments, and gets it ready to ship to clients.
* Called by on_world_reboot_start()
*/
/datum/credits/proc/finalize(var/force = FALSE)
if(finalized && !force)
return
if(!drafted) //In case the world is rebooted without the round ending normally.
draft()
finalize_disclaimerstring() //finalize it after the admins have had time to edit them
finalize_starstring()
if(episode_name == "") //admin might've already set one
pick_name()
finalize_episodestring()
var/scrollytext = episode_string + cast_string + disclaimers_string
var/splashytext = producers_string + star_string
var/list/js_args = list(scrollytext, producers_string, scroll_speed, splash_time, starting_delay, song_link) //arguments for the makeCredits function back in the javascript
finalized = TRUE
js_args = list(scrollytext, splashytext, scroll_speed, splash_time) //arguments for the makeCredits function back in the javascript
log_debug("Sending credit info to all clients...")
/*
* send2clients():
* Take our packaged JS arguments and ship them to clients, BUT DON'T PLAY YET.
* Called by on_world_reboot_start()
*/
/datum/credits/proc/send2clients()
if(isnull(finalized))
stack_trace("PANIC! CREDITS ATTEMPTED TO SEND TO CLIENTS WITHOUT BEING FINALIZED!")
for(var/client/C in clients)
C.show_credits(js_args)
C.download_credits()
/client/proc/show_credits(var/list/js_args)
set waitfor = FALSE
/*
* play2clients:
* Okay, roll'em!
* Called by on_world_reboot_end()
*/
/datum/credits/proc/play2clients()
if(isnull(finalized))
stack_trace("PANIC! CREDITS ATTEMPTED TO PLAY TO CLIENTS WITHOUT BEING FINALIZED!")
for(var/client/C in clients)
C.play_downloaded_credits()
verbs += /client/proc/clear_credits
/*
* on_round_end:
* Called by /gameticker/process() (on normal roundend)
* |-ROUND ENDS--------------------------(60 sec)--------------------------REBOOT STARTS--------(audio_post_delay sec)--------REBOOT ENDS, SERVER SHUTDOWN-|
* ^^^^^ we are here
*/
/datum/credits/proc/on_round_end()
draft()
for(var/client/C in clients)
C.credits_audio(preload_only = TRUE) //Credits preference set to "No Reruns" should still preload, since we still don't know if the episode is a rerun. If audio time comes and the episode is a rerun, then we can start preloading the jingle instead.
src << output(end_credits.file, end_credits.control)
log_debug("[src] received credits info correctly.")
sleep(end_credits.starting_delay)
src << output(list2params(js_args), "[end_credits.control]:makeCredits")
winset(src, end_credits.control, "is-visible=true")
log_debug("[src] is showing credits correctly.")
/*
* on_round_end:
* Called by /world/Reboot(). Round may not have ended normally, so don't assume on_round_end was called!
* |-ROUND ENDS--------------------------(60 sec)--------------------------REBOOT STARTS--------(audio_post_delay sec)--------REBOOT ENDS, SERVER SHUTDOWN-|
* ^^^^^ we are here
*/
/datum/credits/proc/on_world_reboot_start()
if(!drafted) //In case the round did not end normally via smelele.
draft()
if(!finalized) //In case for some unknowable reason an admin vareditting the credits already proccall-finalized them?
finalize()
send2clients()
for(var/client/C in clients)
if(!C.prefs)
continue
switch(C.prefs.credits)
if(CREDITS_ALWAYS)
C.credits_audio()
if(CREDITS_NO_RERUNS) //The time has come to decide. Shall we play credits audio, or preload the jingle audio instead?
if(!is_rerun)
C.credits_audio()
else
C.jingle_audio(preload_only = TRUE)
if(CREDITS_NEVER)
C.jingle_audio(preload_only = TRUE)
else
log_debug("[C] somehow had an unknown credits preference of: [C.prefs.credits]")
/*
* on_world_reboot_end:
* Called by /world/Reboot(), after sleeping for audio_post_delay seconds.
* |-ROUND ENDS--------------------------(60 sec)--------------------------REBOOT STARTS--------(audio_post_delay sec)--------REBOOT ENDS, SERVER SHUTDOWN-|
* ^^^^^ we are here
*/
/datum/credits/proc/on_world_reboot_end()
play2clients()
for(var/client/C in clients)
C.jingle_audio()
/client/proc/clear_credits()
set name = "Skip Credits"
set category = "OOC"
verbs -= /client/proc/clear_credits
src << output(null, "[end_credits.control]:stopItNow")
/datum/credits/proc/pick_name()
var/list/drafted_names = list()
var/list/is_rare_assoc_list = list()
for(var/datum/episode_name/N in episode_names)
drafted_names["[N.thename]"] = N.weight
is_rare_assoc_list["[N.thename]"] = N.rare
episode_name = pickweight(drafted_names)
if(prob(5))
episode_name += ": PART I"
else if(prob(5))
episode_name += ": PART II"
else if(prob(2))
episode_name += ": PART III"
else if(prob(4) && score["time"] > 60 * 60 * 3) //3 hours
episode_name += ": THE FEATURE LENGTH PRESENTATION"
else if(prob(4) && score["time"] < 60 * 30) //30 min
episode_name += ": ABRIDGED"
else if(prob(1))
episode_name += ": NOW IN 3D"
else if(prob(1))
episode_name += ": ON ICE!"
else if(prob(1))
episode_name += ": THE SEASON FINALE"
if(is_rare_assoc_list[episode_name] == TRUE)
is_rerun = FALSE
/datum/credits/proc/finalize_episodestring(var/thename)
var/season = rand(1,22)
var/episodenum = rand(1,17) //Maybe we could do this cumulatively so that the round after 670 becomes 671 etc and the season is just the last 2 numbers of the current IRL year?
episode_string = "<h1>SEASON [season] EPISODE [episodenum]<br>[uppertext(episode_name)]</h1><br><div style='padding-bottom: 75px;'></div>"
log_game("So ends SEASON [season] EPISODE [episodenum] - [uppertext(episode_name)]")
episode_string = "<h1>SEASON [season] EPISODE [episodenum]<br>[episode_name]</h1><br><div style='padding-bottom: 75px;'></div>"
log_game("So ends [is_rerun ? "another rerun of " : ""]SEASON [season] EPISODE [episodenum] - [episode_name]")
/datum/credits/proc/finalize_disclaimerstring()
disclaimers_string = "<div class='disclaimers'>"
@@ -99,7 +185,7 @@ var/global/datum/credits/end_credits = new
disclaimers_string += "[disclaimer]<br>"
disclaimers_string += "</div>"
/datum/credits/proc/generate_producerstring()
/datum/credits/proc/draft_producerstring()
var/list/staff = list("<h1>PRODUCTION STAFF</h1><br>")
var/list/staffjobs = list("Coffee Fetcher", "Cameraman", "Angry Yeller", "Chair Operator", "Choreographer", "Historical Consultant", "Costume Designer", "Chief Editor", "Executive Assistant", "Key Grip")
if(!admins.len)
@@ -118,29 +204,43 @@ var/global/datum/credits/end_credits = new
producers = list("<h1>Directed by</br>[uppertext(director)]</h1>","[jointext(staff,"")]")
for(var/head in data_core.get_manifest_json()["heads"])
producers += "<h1>[head["rank"]]<br>[uppertext(head["name"])]</h1><br>"
if(star)
producers += "<h1>Starring<br>[thebigstar(star)]</h1><br>"
producers_string = ""
for(var/producer in end_credits.producers)
producers_string += "[producer]%n" //%n being an arbitrary "new producer" char we use to split this string back in the javascript
for(var/producer in producers)
producers_string += "[producer]%<splashbreak>" //%<splashbreak> being an arbitrary "new splash card" char we use to split this string back in the javascript
/datum/credits/proc/generate_caststring()
/datum/credits/proc/draft_star()
if(star)
star = thebigstar(star)
else if(most_talked)
star = thebigstar(most_talked) //We want this ran now, in case the star gibs before the credits roll etc
/datum/credits/proc/finalize_starstring()
if(star_string)
return
star_string = "<h1>Starring<br>[star]</h1><br>%<splashbreak>" //%<splashbreak> being an arbitrary "new splash card" char we use to split this string back in the javascript
/datum/credits/proc/draft_caststring()
cast_string = "<h1>CAST:</h1><br><h2>(in order of appearance)</h2><br>"
cast_string += "<table class='crewtable'>"
for(var/mob/living/carbon/human/H in living_mob_list|dead_mob_list)
if(H.iscorpse || (H.timeofdeath && H.timeofdeath < 5 MINUTES)) //don't mention these losers (prespawned corpses mostly)
for(var/mob/living/carbon/human/H in mob_list)
if(!H.key || H.iscorpse)
continue
if(!star || H.talkcount > star.talkcount)
star = H
if(!most_talked || H.talkcount > most_talked.talkcount)
most_talked = H
cast_string += "[gender_credits(H)]"
for(var/mob/living/silicon/S in mob_list)
if(!S.key)
continue
cast_string += "[silicon_credits(S)]"
cast_string += "</table><br>"
cast_string += "<div class='disclaimers'>"
var/list/corpses = list()
for(var/mob/living/carbon/human/H in dead_mob_list)
if(H.iscorpse || (H.timeofdeath && H.timeofdeath < 5 MINUTES)) //no prespawned corpses
if(!H.key || H.iscorpse)
continue
else if(H.real_name)
corpses += H.real_name
@@ -151,22 +251,33 @@ var/global/datum/credits/end_credits = new
/proc/gender_credits(var/mob/living/carbon/human/H)
if(H.mind && H.mind.key)
return "<tr><td class='actorname'>[uppertext(H.mind.key)]</td><td class='actorsegue'> as </td><td class='actorrole'>[H.real_name], [H.get_assignment()]</td></tr>"
var/assignment = H.get_assignment(if_no_id = "", if_no_job = "")
return "<tr><td class='actorname'>[uppertext(H.mind.key)]</td><td class='actorsegue'> as </td><td class='actorrole'>[H.real_name][assignment == "" ? "" : ", [assignment]"]</td></tr>"
else
var/t_him = "Them"
if(H.gender == MALE)
t_him = "Him"
else if(H.gender == FEMALE)
t_him = "Her"
return "<tr><td class='actorname'>[uppertext(H.real_name)]</td><td class='actorsegue'> as </td><td class='actorrole'>[t_him]self</td></tr>"
return "<tr><td class='actorname'>[uppertext(H.real_name)]</td><td class='actorsegue'> as </td><td class='actorrole'>[t_him == "Them" ? "Themselves" : "[t_him]self"]</td></tr>"
/proc/thebigstar(var/mob/living/carbon/human/H)
if(H.mind && H.mind.key)
return "[uppertext(H.mind.key)] as [H.real_name]"
/proc/silicon_credits(var/mob/living/silicon/S)
if(S.mind && S.mind.key)
return "<tr><td class='actorname'>[uppertext(S.mind.key)]</td><td class='actorsegue'> as </td><td class='actorrole'>[S.name]</td></tr>"
else
var/t_him = "Them"
if(H.gender == MALE)
t_him = "Him"
else if(H.gender == FEMALE)
t_him = "Her"
return "[uppertext(H.real_name)] as [t_him]self"
return "<tr><td class='actorname'>[uppertext(S.name)]</td><td class='actorsegue'> as </td><td class='actorrole'>Itself</td></tr>"
/proc/thebigstar(var/star)
if(istext(star))
return star
if(ismob(star))
var/mob/M = star
if(M.mind && M.mind.key)
return "[uppertext(M.mind.key)] as [M.real_name]"
else
var/t_him = "Them"
if(M.gender == MALE)
t_him = "Him"
else if(M.gender == FEMALE)
t_him = "Her"
return "[uppertext(M.real_name)] as [t_him == "Them" ? "Themselves" : "[t_him]self"]"

View File

@@ -57,57 +57,92 @@
</style>
</head>
<body>
<div id="soundplayer" style="display: none;">
<audio autoplay><source src="http://ss13.moe:3000/Pomf/vgstation-media/raw/master/shuttle/Frolic%20-%20Luciano%20Michelini.mp3" type="audio/mpeg"></audio>
<div id="sounddiv">
<!-- the soundplayer gets added here via javascript! !-->
</div>
<table id="container"> <!-- Yes we use a table to center ourselves. StackOverflow says this is not acceptable practice past 2012 but we're operating with 2009 tech so... !-->
<tr>
<td class="letterboxer"></td>
<td id="splash">
IF YOU CAN SEE THIS, TELL A CODER WHAT HAPPENED!
HELPFUL DETAILS INCLUDE:
WAS THE ROUNDEND DELAYED?
WAS THE SERVER MANUALLY REBOOTED?
DID YOU PLAY MORE THAN ONE ROUND IN A ROW WITHOUT CLOSING THE GAME?
DID CREDITS FAIL TO DISPLAY FOR YOU LAST ROUND?
DID THE CREDITS AUDIO FAIL TO PLAY FOR YOU?
IS YOUR CONNECTION SLOW/WERE YOU TORRENTING DOLPHIN PORN JUST NOW?
DID THIS TEXT DISPLAY FOR ANYONE ELSE?
WHAT ARE YOUR CREDITS AND JINGLE PREFERENCES SET TO?
</td>
<td class="letterboxer"></td>
</tr>
<tr>
<td class="letterboxer"></td>
<td id="marquee">
IF YOU CAN SEE THIS, REALLY TELL A CODER WHAT HAPPENED!
IF YOU CAN SEE THIS, THE TEXT HAS STARTED SCROLLING,
SO REALLY TELL A CODER WHAT HAPPENED!
</td>
<td class="letterboxer"></td>
</tr>
</table>
<script type="text/javascript">
//Runs a route within byond, client or server side. Consider this "ehjax" for byond.
function runByond(uri) {
window.location = uri;
}
var producers = [];
var lastinterval;
var lastinterval; //just for the auto-suicide failsafe
var scrollSpeed = 25; //miliseconds between each pixel we go up
var splashTime = 2000; //in miliseconds
var started = 0;
var initialized = 0;
function setScrollingText(text){
document.getElementById("marquee").innerHTML = text;
}
function setProducers(text){
producers = text.split("%n");
producers = producers.slice(0, -1); //get rid of the last %n
producers = text.split("%<splashbreak>");
producers = producers.slice(0, -1); //get rid of the last %<splashbreak>
}
function makeCredits(scrollyString, producersString, scrollSpeed, splashTime, startingDelay, songLink){
if (splashTime === undefined) {
splashTime = 2000;
function setAudio(link, autoplay){
var sound = document.getElementById("sounddiv");
if(autoplay == 1){
sound.innerHTML = "<audio id='soundplayer' autoplay=''><source src='" + link + "' type='audio/mpeg'></audio>";
}
splashTime = parseInt(splashTime); //Just in case
else{
sound.innerHTML = "<audio id='soundplayer' preload='auto'><source src='" + link + "' type='audio/mpeg'></audio>";
}
}
if (scrollSpeed === undefined) {
scrollSpeed = 25;
}
scrollSpeed = parseInt(scrollSpeed); //Just in case
function setupCredits(scrollyString, producersString, newScrollSpeed, newSplashTime){
if(newSplashTime !== undefined) {splashTime = parseInt(newSplashTime)}
if(newScrollSpeed !== undefined) {scrollSpeed = parseInt(newScrollSpeed)}
setScrollingText(scrollyString);
setProducers(producersString);
initialized = 1;
}
function startAudio(){
var sound = document.getElementById("soundplayer");
sound.play();
}
function startCredits(){
if(started == 1 || initialized == 0)
return;
started = 1;
runByond('byond://winset?id=mapwindow.credits;is-visible=true');
splashLoop(producers, 0, splashTime);
setTimeout(rollMarquee, producers.length*splashTime, scrollSpeed);
}
function splashLoop(arr, index, time) {
if (index === arr.length){
function splashLoop(arr, index, time){
if(index === arr.length){
return;
}
document.getElementById("splash").innerHTML = arr[index];
@@ -120,19 +155,23 @@
lastinterval = setInterval(function () {
bottom = bottom + 1;
div.style.bottom = bottom + "px";
if(bottom > 3000){ //RUNAWAY CREDIT ALART - no seriously this will keep going if the player doesn't close the game between rounds
//document.documentElement.innerHTML = "<textarea rows='4' cols='50'>" + document.documentElement.innerHTML + "</textarea>"; clearInterval(lastinterval); return; //debugging
if(bottom > 3000){ //RUNAWAY CREDIT ALART - no seriously this might keep going if the server doesn't start back up
//debugMe()
clearInterval(lastinterval);
stopItNow();
commitSuicide();
return;
}
}, speed);
}
function stopItNow(){
var sound = document.getElementById("soundplayer");
sound.parentNode.removeChild(sound);
window.location = 'byond://winset?id=mapwindow.credits;is-visible=false';
function debugMe(){
document.documentElement.innerHTML = "<textarea rows='4' cols='50'>" + document.documentElement.innerHTML + "</" + "textarea>";
runByond('byond://winset?id=mapwindow.credits;is-visible=true');
};
function commitSuicide(){
document.documentElement.innerHTML = '';
runByond('byond://winset?id=mapwindow.credits;is-visible=false');
};
</script>
</body>

View File

@@ -0,0 +1,73 @@
/client/proc/clear_credits()
winset(src, end_credits.control, "is-visible=false")
//The following line resets the credit's browser back to the pre-script-populated credits.html file, which still has for example the javascript loaded.
//This technically does cause a mysterious overhead of having a 5kb html file in an invisible browser for your entire play session.
//Will it cause problems? Probably not, but this is BYOND, so if any mysterious invisible HTML browser problem starts to happen down the line... remember this comment.
src << output(end_credits.file, end_credits.control)
/client/proc/download_credits()
if(prefs.credits == CREDITS_NEVER)
return
src << output(list2params(end_credits.js_args), "[end_credits.control]:setupCredits")
received_credits = TRUE
/client/proc/play_downloaded_credits()
if(prefs.credits == CREDITS_NEVER)
return
if(prefs.credits == CREDITS_NO_RERUNS && end_credits.is_rerun)
return
if(!received_credits)
log_debug("[src] tried to play credits without having ever received them! Credits preference: [prefs.credits]")
return
src << output("", "[end_credits.control]:startCredits") //Execute the startCredits() function in credits.html with no parameters.
/client/proc/credits_audio(var/preload_only = FALSE)
if(prefs.credits == CREDITS_NEVER)
return
if(preload_only)
src << output(list2params(list(end_credits.audio_link, FALSE)), "[end_credits.control]:setAudio")
received_roundend_audio = TRUE
else
if(prefs.credits == CREDITS_NO_RERUNS && end_credits.is_rerun)
return
if(received_roundend_audio)
src << output("", "[end_credits.control]:startAudio") //Execute the playAudio() function in credits.html with no parameters.
else
src << output(list2params(list(end_credits.audio_link, TRUE)), "[end_credits.control]:setAudio")
/client/proc/jingle_audio(var/preload_only = FALSE)
if(prefs.credits == CREDITS_ALWAYS)
return
var/link = ""
switch(prefs.jingle)
if(JINGLE_NEVER)
return
if(JINGLE_CLASSIC)
link = pick(end_credits.classic_roundend_jingles)
if(JINGLE_ALL)
link = pick(end_credits.classic_roundend_jingles + end_credits.new_roundend_jingles)
if(!link)
log_debug("[src] somehow had a null jingle link! Jingle preference: [prefs.jingle]")
if(preload_only)
src << output(list2params(list(link, FALSE)), "[end_credits.control]:setAudio")
received_roundend_audio = TRUE
else
if(prefs.credits == CREDITS_NO_RERUNS && !end_credits.is_rerun)
return
if(received_roundend_audio)
src << output("", "[end_credits.control]:startAudio") //Execute the playAudio() function in credits.html with no parameters.
else
src << output(list2params(list(link, TRUE)), "[end_credits.control]:setAudio")
/*
/client/verb/credits_debug()
set name = "Debug Credits"
set category = "OOC"
src << output("", "[end_credits.control]:debugMe")
winset(src, end_credits.control, "is-visible=true")
*/

View File

@@ -109,8 +109,6 @@
episode_names += new /datum/episode_name/rare("MY HEART WILL GO ON", "[score["heartattacks"]] hearts were reanimated and burst out of someone's chest this round.", min(1500, score["heartattacks"]*150))
if(score["richestcash"] > 30000)
episode_names += new /datum/episode_name/rare("[pick("WAY OF THE WALLET", "THE IRRESISTIBLE RISE OF [uppertext(score["richestname"])]", "PRETTY PENNY", "IT'S THE ECONOMY, STUPID")]", "Scrooge Mc[score["richestkey"]] racked up [score["richestcash"]] credits this round.", min(450, score["richestcash"]/500))
if(star && star.times_cloned > 2)
episode_names += new /datum/episode_name/rare("[uppertext(star.real_name)] MUST DIE", "The star of the show, [star.real_name], was cloned [star.times_cloned] times.", min(500, star.times_cloned*50))
if(score["deadaipenalty"] > 3)
episode_names += new /datum/episode_name/rare("THE ONE WHERE [score["deadaipenalty"]] AIS DIE", "That's a lot of dead AIs.", min(1500, score["deadaipenalty"]*150))
if(score["lawchanges"] > 10)

View File

@@ -0,0 +1,13 @@
/datum/migration/sqlite/ss13_prefs/_014
id = 14
name = "Add Credits Preference"
/datum/migration/sqlite/ss13_prefs/_014/up()
if(!hasColumn("client","credits"))
return execute("ALTER TABLE `client` ADD COLUMN credits TEXT DEFAULT 'Always'")
return TRUE
/datum/migration/sqlite/ss13_prefs/_014/down()
if(hasColumn("client","credits"))
return execute("ALTER TABLE `client` DROP COLUMN credits")
return TRUE

View File

@@ -0,0 +1,13 @@
/datum/migration/sqlite/ss13_prefs/_015
id = 15
name = "Add Jingle Preference"
/datum/migration/sqlite/ss13_prefs/_015/up()
if(!hasColumn("client","jingle"))
return execute("ALTER TABLE `client` ADD COLUMN jingle TEXT DEFAULT 'Classics'")
return TRUE
/datum/migration/sqlite/ss13_prefs/_015/down()
if(hasColumn("client","jingle"))
return execute("ALTER TABLE `client` DROP COLUMN jingle")
return TRUE

View File

@@ -271,11 +271,11 @@ var/savefile/panicfile
stop_all_media()
if(!end_credits.generated)
end_credits.on_roundend()
end_credits.rollem()
end_credits.on_world_reboot_start()
sleep(end_credits.starting_delay + end_credits.post_delay)
sleep(max(10, end_credits.audio_post_delay))
end_credits.on_world_reboot_end()
for(var/client/C in clients)
if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite

View File

@@ -1342,6 +1342,7 @@
#include "code\modules\context_click\remote.dm"
#include "code\modules\credits\credit_disclaimers.dm"
#include "code\modules\credits\credits.dm"
#include "code\modules\credits\credits_clientprocs.dm"
#include "code\modules\credits\episode_name.dm"
#include "code\modules\customitems\item_spawning.dm"
#include "code\modules\customitems\definitions\base.dm"
@@ -1505,6 +1506,8 @@
#include "code\modules\migrations\SS13_Prefs\011-add-flavor.dm"
#include "code\modules\migrations\SS13_Prefs\012-add-pull-pref.dm"
#include "code\modules\migrations\SS13_Prefs\013-add-bank-pref.dm"
#include "code\modules\migrations\SS13_Prefs\014-add-credits-pref.dm"
#include "code\modules\migrations\SS13_Prefs\015-add-jingle_pref.dm"
#include "code\modules\migrations\SS13_Prefs\_base.dm"
#include "code\modules\mining\abandonedcrates.dm"
#include "code\modules\mining\debug_shit.dm"
@@ -2450,7 +2453,7 @@
#include "maprendering\maprendering.dm"
#include "maps\_map.dm"
#include "maps\_map_override.dm"
#include "maps\tgstation.dm"
#include "maps\test_box.dm"
#include "maps\defficiency\areas.dm"
#include "maps\packedstation\telecomms.dm"
#include "maps\randomvaults\dance_revolution.dm"