diff --git a/baystation12.dme b/baystation12.dme index c82f08c0d55..0bdee3aed5c 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -483,6 +483,7 @@ #include "code\game\machinery\magnet.dm" #include "code\game\machinery\morgue.dm" #include "code\game\machinery\navbeacon.dm" +#include "code\game\machinery\newscaster.dm" #include "code\game\machinery\OpTable.dm" #include "code\game\machinery\overview.dm" #include "code\game\machinery\portable_turret.dm" diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm new file mode 100644 index 00000000000..dd9176d0476 --- /dev/null +++ b/code/game/machinery/newscaster.dm @@ -0,0 +1,846 @@ +//############################################## +//################### NEWSCASTERS BE HERE! #### +//###-Agouri################################### + +/datum/feed_message + var/author="" + var/body="" + //var/parent_channel + var/backup_body="" + var/backup_author="" + +/datum/feed_channel + var/channel_name="" + var/list/datum/feed_message/messages = list() + //var/message_count = 0 + var/locked=0 + var/author="" + var/backup_author="" + var/censored=0 + //var/page = null //For newspapers + +var/list/obj/machinery/newscaster/allCasters = list() //list that will contain reference to all newscasters in existence. + + +/obj/machinery/newscaster + name = "Newscaster" + desc = "A standard Nanotrasen-licensed newsfeed handler for use in commercial space stations. All the news you absolutely have no use for, in one place!" + icon = 'terminals.dmi' + icon_state = "newscaster_normal" + var/isbroken = 0 //1 if someone banged it with something heavy + var/ispowered = 1 //starts powered, changes with power_change() + var/list/datum/feed_channel/channel_list = list() //This list will contain the names of the feed channels. Each name will refer to a data region where the messages of the feed channels are stored. + var/screen = 0 //Or maybe I'll make it into a list within a list afterwards... whichever I prefer, go fuck yourselves :3 + // 0 = welcome screen - main menu + // 1 = view feed channels + // 2 = create feed channel + // 3 = create feed story + // 4 = feed story submited sucessfully + // 5 = feed channel created successfully + // 6 = ERROR: Cannot create feed story + // 7 = ERROR: Cannot create feed channel + // 8 = print newspaper + // 9 = viewing channel feeds + // 10 = censor feed story + // 11 = censor feed channel + //Holy shit this is outdated, made this when I was still starting newscasters :3 + var/paper_remaining = 0 + var/securityCaster = 0 + var/unit_no = 0 //Each newscaster has a unit_no + // 0 = Caster cannot be used to issue wanted posters + // 1 = the opposite + var/datum/feed_message/wanted //We're gonna use a feed_message to store data of the wanted person because fields are similar + var/wanted_issue = 0 + // 0 = there's no WANTED issued, we don't need a special icon_state + // 1 = Guess what. + var/alert = 0 + // 0 = there hasn't been a news/wanted update in the last minutes + // 1 = there has + var/scanned_user = "Unknown" //Will contain the name of the person who currently uses the newscaster + var/msg = ""; //Feed message + var/channel_name = ""; //the feed channel which will be receiving the feed, or being created + var/c_locked=0; + var/hitstaken = 0 //Death at 3 hits from an item with force>=15 + var/datum/feed_channel/viewing_channel = null + luminosity = 0 + anchored = 1 + + +/obj/machinery/newscaster/security_unit + name = "Security Newscaster" + securityCaster = 1 + + +/obj/machinery/newscaster/New() //Right, apparently it's good to have a New() for machinery for some sort of global machine list... + allCasters += src + src.paper_remaining = 15 // Will probably change this to something better + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) // Let's give it an appropriate unit number + src.unit_no++ + src.update_icon() //for any custom ones on the map... + +/obj/machinery/newscaster/Del() + allCasters -= src + ..() + +/obj/machinery/newscaster/update_icon() + if(!ispowered || isbroken) + icon_state = "newscaster_off" + if(isbroken) //If the thing is smashed, add crack overlay on top of the unpowered sprite. + src.overlays = null + src.overlays += image(src.icon, "crack3") + return + + src.overlays = null //reset overlays + if(alert) //new message alert overlay + src.overlays += "newscaster_alert" + if(hitstaken > 0) //Cosmetic damage overlay + src.overlays += image(src.icon, "crack[hitstaken]") + + if(wanted_issue) //wanted icon state + icon_state = "newscaster_wanted" + return + + icon_state = "newscaster_normal" + return + +/obj/machinery/newscaster/power_change() + if(isbroken) //Broken shit can't be powered. + return + if( src.powered() ) + src.ispowered = 1 + stat &= ~NOPOWER + src.update_icon() + else + spawn(rand(0, 15)) + src.ispowered = 0 + stat |= NOPOWER + src.update_icon() + + +/obj/machinery/newscaster/ex_act(severity) + switch(severity) + if(1.0) + del(src) + return + if(2.0) + src.isbroken=1 + if(prob(50)) + del(src) + else + src.update_icon() //can't place it above the return and outside the if-else. or we might get runtimes of null.update_icon() if(prob(50)) goes in. + return + else + if(prob(50)) + src.isbroken=1 + src.update_icon() + return + return + +/obj/machinery/newscaster/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/newscaster/attack_hand(mob/user as mob) + if(!src.ispowered || src.isbroken) + return + if(istype(user, /mob/living/carbon/human) ) + var/mob/living/carbon/human/human_user = user + var/dat + dat = text("Newscaster

Newscaster Unit #[src.unit_no]

") + + src.scan_user(human_user) //Newscaster scans you + + switch(screen) + if(0) + dat += "Welcome to Newscasting Unit #[src.unit_no].
Interface & News networks Operational." + dat += "
Property of Nanotransen Inc" + if(src.wanted_issue) + dat+= "
Read Wanted Issue" + dat+= "

Create Feed Channel" + dat+= "
View Feed Channels" + dat+= "
Submit new Feed story" + dat+= "
Print newspaper" + dat+= "
Re-scan User" + dat+= "

Exit" + if(src.securityCaster) + var/wanted_already = 0 + for(var/obj/machinery/newscaster/N in allCasters) + if(N.wanted_issue) + wanted_already = 1 + break + dat+="
Feed Security functions:
" + dat+="
[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue" + dat+="
Censor Feed Stories" + dat+="
Mark Feed Channel with Nanotrasen D-Notice" + dat+="

The newscaster recognises you as: [src.scanned_user]" + if(1) + dat+= "Station Feed Channels
" + if( isemptylist(src.channel_list) ) + dat+="No active channels found..." + else + for(var/datum/feed_channel/CHANNEL in src.channel_list) + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
" + /*for(var/datum/feed_channel/CHANNEL in src.channel_list) + dat+="[CHANNEL.channel_name]:
\[created by: [CHANNEL.author]\]

" + if( isemptylist(CHANNEL.messages) ) + dat+="No feed messages found in channel...

" + else + for(var/datum/feed_message/MESSAGE in CHANNEL.messages) + dat+="-[MESSAGE.body]
\[Story by [MESSAGE.author]\]
"*/ + + dat+="

Refresh" + dat+="
Back" + if(2) + dat+="Creating new Feed Channel..." + dat+="
Channel Name: [src.channel_name]
" + dat+="Channel Author: [src.scanned_user]
" + dat+="Will Accept Public Feeds: [(src.c_locked) ? ("NO") : ("YES")]

" + dat+="
Submit

Cancel
" + if(3) + dat+="Creating new Feed Message..." + dat+="
Receiving Channel: [src.channel_name]
" //MARK + dat+="Message Author: [src.scanned_user]
" + dat+="Message Body: [src.msg]
" + dat+="
Submit

Cancel
" + if(4) + dat+="Feed story successfully submitted to [src.channel_name].

" + dat+="
Return
" + if(5) + dat+="Feed Channel [src.channel_name] created successfully.

" + dat+="
Return
" + if(6) + dat+="ERROR: Could not submit Feed story to Network.

" + if(src.channel_name=="") + dat+="•Invalid receiving channel name.
" + if(src.scanned_user=="Unknown") + dat+="•Channel author unverified.
" + if(src.msg == "" || src.msg == "\[REDACTED\]") + dat+="•Invalid message body.
" + + dat+="
Return
" + if(7) + dat+="ERROR: Could not submit Feed Channel to Network.

" + var/list/existing_channels = list() //Let's get dem existing channels + var/list/existing_authors = list() + for(var/datum/feed_channel/FC in src.channel_list) + existing_channels += FC.channel_name + if(FC.author == "\[REDACTED\]") + existing_authors += FC.backup_author + else + existing_authors +=FC.author + if(src.scanned_user in existing_authors) + dat+="•There already exists a Feed channel under your name.
" + if(src.channel_name=="" || src.channel_name == "\[REDACTED\]") + dat+="•Invalid channel name.
" + if(src.channel_name in existing_channels) + dat+="•Channel name already in use.
" + if(src.scanned_user=="Unknown") + dat+="•Channel author unverified.
" + dat+="
Return
" + if(8) + var/total_num=length(src.channel_list) + var/active_num=total_num + var/message_num=0 + for(var/datum/feed_channel/FC in src.channel_list) + if(!FC.censored) + message_num += length(FC.messages) + else + active_num-- + dat+="Network currently serves a total of [total_num] Feed channels, [active_num] of which are active, and a total of [message_num] Feed Stories." //TODO: CONTINUE + dat+="

Liquid Paper remaining: [(src.paper_remaining) *100 ] cm^3" + dat+="

Print Paper" + dat+="
Cancel" + if(9) + dat+="[src.viewing_channel.channel_name]: \[created by: [src.viewing_channel.author]\]
" + if(src.viewing_channel.censored) + dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.
" + dat+="No further feed story additions are allowed while the D-Notice is in effect.

" + else + if( isemptylist(src.viewing_channel.messages) ) + dat+="No feed messages found in channel...
" + else + for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) + dat+="-[MESSAGE.body]
\[Story by [MESSAGE.author]\]

" + dat+="

Refresh" + dat+="
Back" + if(10) + dat+="Nanotrasen Feed Censorship Tool
" + dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
" + dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.
" + dat+="
Select Feed channel to get Stories from:
" + if(isemptylist(src.channel_list)) + dat+="No feed channels found active...
" + else + for(var/datum/feed_channel/CHANNEL in src.channel_list) + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
" + dat+="
Cancel" + if(11) + dat+="Nanotrasen D-Notice Handler
" + dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's" + dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed" + dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
" + if(isemptylist(src.channel_list)) + dat+="No feed channels found active...
" + else + for(var/datum/feed_channel/CHANNEL in src.channel_list) + dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
" + + dat+="
Back" + if(12) + dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
" + dat+="[(src.viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
" + + + if( isemptylist(src.viewing_channel.messages) ) + dat+="No feed messages found in channel...
" + else + for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) + dat+="-[MESSAGE.body]
\[Story by [MESSAGE.author]\]
" + dat+="[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
" + dat+="
Back" + if(13) + dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
" + dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
" + if(src.viewing_channel.censored) + dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.
" + dat+="No further feed story additions are allowed while the D-Notice is in effect.

" + else + if( isemptylist(src.viewing_channel.messages) ) + dat+="No feed messages found in channel...
" + else + for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) + dat+="-[MESSAGE.body]
\[Story by [MESSAGE.author]\]
" + + dat+="
Back" + if(14) + dat+="Wanted Issue Handler:" + var/wanted_already = 0 + var/end_param = 1 + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) + if(NEWSCASTER.wanted_issue) + wanted_already = 1 + end_param = 2 + break + if(wanted_already) + dat+="
A wanted issue is already in Feed Circulation. You can edit or cancel it below.
" + dat+="
" + dat+="Criminal Name: [src.channel_name]
" + dat+="Description: [src.msg]
" + dat+="Wanted Issue created by: [src.scanned_user]
" + dat+="
[(wanted_already) ? ("Edit Issue") : ("Submit")]" + if(wanted_already) + dat+="
Take down Issue" + dat+="
Cancel" + if(15) + dat+="Wanted issue for [src.channel_name] is now in Network Circulation.

" + dat+="
Return
" + if(16) + dat+="ERROR: Wanted Issue rejected by Network.

" + if(src.channel_name=="" || src.channel_name == "\[REDACTED\]") + dat+="•Invalid name for person wanted.
" + if(src.scanned_user=="Unknown") + dat+="•Issue author unverified.
" + if(src.msg == "" || src.msg == "\[REDACTED\]") + dat+="•Invalid description.
" + dat+="
Return
" + if(17) + dat+="Wanted Issue successfully deleted from Circulation
" + dat+="
Return
" + if(18) + dat+="-- STATIONWIDE WANTED ISSUE --
\[Submitted by: [src.wanted.backup_author]\]
" + dat+="Criminal: [src.wanted.author]
" + dat+="Description: [src.wanted.body]
" + dat+="
Back
" + if(19) + dat+="Wanted issue for [src.channel_name] successfully edited.

" + dat+="
Return
" + if(20) + dat+="Printing successfull. Please receive your newspaper from the bottom of the machine.

" + dat+="Return" + if(21) + dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnell to refill machine storage.

" + dat+="Return" + else + dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" + + + human_user << browse(dat, "window=newscaster_main;size=400x600") + onclose(human_user, "newscaster_main") + + /*if(src.isbroken) //debugging shit + return + src.hitstaken++ + if(src.hitstaken==3) + src.isbroken = 1 + src.update_icon()*/ + + +/obj/machinery/newscaster/Topic(href, href_list) + if(..()) + return + if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon/ai))) + usr.machine = src + if(href_list["set_channel_name"]) + src.channel_name = strip_html(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", "")) + while (findtext(src.channel_name," ") == 1) + src.channel_name = copytext(src.channel_name,2,lentext(src.channel_name)+1) + src.updateUsrDialog() + //src.update_icon() + + else if(href_list["set_channel_lock"]) + src.c_locked = !src.c_locked + src.updateUsrDialog() + //src.update_icon() + + else if(href_list["submit_new_channel"]) + var/list/existing_channels = list() + var/list/existing_authors = list() + for(var/datum/feed_channel/FC in src.channel_list) + existing_channels += FC.channel_name + if(FC.author == "\[REDACTED\]") + existing_authors += FC.backup_author + else + existing_authors +=FC.author + if(src.channel_name == "" || src.channel_name == "\[REDACTED\]" || src.scanned_user == "Unknown" || (src.channel_name in existing_channels) || (src.scanned_user in existing_authors) ) + src.screen=7 + else + var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel") + if(choice=="Confirm") + var/datum/feed_channel/newChannel = new /datum/feed_channel + newChannel.channel_name = src.channel_name + newChannel.author = src.scanned_user + newChannel.locked = c_locked + feedback_inc("newscaster_channels",1) + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) //Let's add the new channel in all casters. + NEWSCASTER.channel_list += newChannel //Now that it is sane, get it into the list. + src.screen=5 + src.updateUsrDialog() + //src.update_icon() + + else if(href_list["set_channel_receiving"]) + //var/list/datum/feed_channel/available_channels = list() + var/list/available_channels = list() + for(var/datum/feed_channel/F in src.channel_list) + if( (!F.locked || F.author == scanned_user) && !F.censored) + available_channels += F.channel_name + src.channel_name = strip_html(input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels ) + src.updateUsrDialog() + + else if(href_list["set_new_message"]) + src.msg = strip_html(input(usr, "Write your Feed story", "Network Channel Handler", "")) + while (findtext(src.msg," ") == 1) + src.msg = copytext(src.msg,2,lentext(src.msg)+1) + src.updateUsrDialog() + + else if(href_list["submit_new_message"]) + if(src.msg =="" || src.msg=="\[REDACTED\]" || src.scanned_user == "Unknown" || src.channel_name == "" ) + src.screen=6 + else + var/datum/feed_message/newMsg = new /datum/feed_message + newMsg.author = src.scanned_user + newMsg.body = src.msg + feedback_inc("newscaster_stories",1) + for(var/datum/feed_channel/FC in src.channel_list) + if(FC.channel_name == src.channel_name) + FC.messages += newMsg // To avoid further confusion, this one for adds the message to all existing newscasters' channel_list's channels. + break // Another for to go through newscasters is not needed. Due to the nature of submit_new_CHANNEL, every reference + src.screen=4 // to a channel in ANY newscaster is the same. Editing one will edit them all. + + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) + NEWSCASTER.newsAlert(src.channel_name) + + src.updateUsrDialog() + + else if(href_list["create_channel"]) + src.screen=2 + src.updateUsrDialog() + + else if(href_list["create_feed_story"]) + src.screen=3 + src.updateUsrDialog() + + else if(href_list["menu_paper"]) + src.screen=8 + src.updateUsrDialog() + else if(href_list["print_paper"]) + if(!src.paper_remaining) + src.screen=21 + else + src.print_paper() + src.screen = 20 + src.updateUsrDialog() + + else if(href_list["menu_censor_story"]) + src.screen=10 + src.updateUsrDialog() + + else if(href_list["menu_censor_channel"]) + src.screen=11 + src.updateUsrDialog() + + else if(href_list["menu_wanted"]) + var/already_wanted = 0 + for(var/obj/machinery/newscaster/N in allCasters) + if(N.wanted_issue) + already_wanted = 1 + break + if(already_wanted) + src.channel_name = src.wanted.author + src.msg = src.wanted.body + src.screen = 14 + src.updateUsrDialog() + + else if(href_list["set_wanted_name"]) + src.channel_name = strip_html(input(usr, "Provide the name of the Wanted person", "Network Security Handler", "")) + while (findtext(src.channel_name," ") == 1) + src.channel_name = copytext(src.channel_name,2,lentext(src.channel_name)+1) + src.updateUsrDialog() + + else if(href_list["set_wanted_desc"]) + src.msg = strip_html(input(usr, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler", "")) + while (findtext(src.msg," ") == 1) + src.msg = copytext(src.msg,2,lentext(src.msg)+1) + src.updateUsrDialog() + + else if(href_list["submit_wanted"]) + var/input_param = text2num(href_list["submit_wanted"]) + if(src.msg == "" || src.channel_name == "" || src.scanned_user == "Unknown") + src.screen = 16 + else + var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel") + if(choice=="Confirm") + if(input_param==1) + var/datum/feed_message/WANTED = new /datum/feed_message + WANTED.author = src.channel_name + WANTED.body = src.msg + WANTED.backup_author = src.scanned_user //I know, a bit wacky + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) + NEWSCASTER.wanted = WANTED + NEWSCASTER.wanted_issue = 1 + NEWSCASTER.newsAlert() + NEWSCASTER.update_icon() + src.screen = 15 + else + src.wanted.author = src.channel_name + src.wanted.body = src.msg + src.wanted.backup_author = src.scanned_user + src.screen = 19 + + src.updateUsrDialog() + + else if(href_list["cancel_wanted"]) + var/choice = alert("Please confirm Wanted Issue removal","Network Security Handler","Confirm","Cancel") + if(choice=="Confirm") + for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) + NEWSCASTER.wanted_issue = 0 + NEWSCASTER.wanted = null + NEWSCASTER.update_icon() + src.screen=17 + src.updateUsrDialog() + + else if(href_list["view_wanted"]) + src.screen=18 + src.updateUsrDialog() + else if(href_list["censor_channel_author"]) + var/datum/feed_channel/FC = locate(href_list["censor_channel_author"]) + if(FC.author != "\[REDACTED\]") + FC.backup_author = FC.author + FC.author = "\[REDACTED\]" + else + FC.author = FC.backup_author + src.updateUsrDialog() + + else if(href_list["censor_channel_story_author"]) + var/datum/feed_message/MSG = locate(href_list["censor_channel_story_author"]) + if(MSG.author != "\[REDACTED\]") + MSG.backup_author = MSG.author + MSG.author = "\[REDACTED\]" + else + MSG.author = MSG.backup_author + src.updateUsrDialog() + + else if(href_list["censor_channel_story_body"]) + var/datum/feed_message/MSG = locate(href_list["censor_channel_story_body"]) + if(MSG.body != "\[REDACTED\]") + MSG.backup_body = MSG.body + MSG.body = "\[REDACTED\]" + else + MSG.body = MSG.backup_body + src.updateUsrDialog() + + else if(href_list["pick_d_notice"]) + var/datum/feed_channel/FC = locate(href_list["pick_d_notice"]) + src.viewing_channel = FC + src.screen=13 + src.updateUsrDialog() + + else if(href_list["toggle_d_notice"]) + var/datum/feed_channel/FC = locate(href_list["toggle_d_notice"]) + FC.censored = !FC.censored + src.updateUsrDialog() + + else if(href_list["view"]) + src.screen=1 + src.updateUsrDialog() + + else if(href_list["setScreen"]) //Brings us to the main menu and resets all fields~ + src.screen = text2num(href_list["setScreen"]) + if (src.screen == 0) + src.scanned_user = "Unknown"; + msg = ""; + src.c_locked=0; + channel_name=""; + src.viewing_channel = null + src.updateUsrDialog() + + else if(href_list["show_channel"]) + var/datum/feed_channel/FC = locate(href_list["show_channel"]) + src.viewing_channel = FC + src.screen = 9 + src.updateUsrDialog() + + else if(href_list["pick_censor_channel"]) + var/datum/feed_channel/FC = locate(href_list["pick_censor_channel"]) + src.viewing_channel = FC + src.screen = 12 + src.updateUsrDialog() + + else if(href_list["refresh"]) + src.updateUsrDialog() + + +/obj/machinery/newscaster/attackby(obj/item/I as obj, mob/user as mob) + +/* if (istype(I, /obj/item/weapon/card/id) || istype(I, /obj/item/device/pda) ) //Name verification for channels or messages + if(src.screen == 4 || src.screen == 5) + if( istype(I, /obj/item/device/pda) ) + var/obj/item/device/pda/P = I + if(P.id) + src.scanned_user = "[P.id.registered] ([P.id.assignment])" + src.screen=2 + else + var/obj/item/weapon/card/id/T = I + src.scanned_user = text("[T.registered] ([T.assignment])") + src.screen=2*/ //Obsolete after autorecognition + + if (src.isbroken) + playsound(src.loc, 'hit_on_shattered_glass.ogg', 100, 1) + for (var/mob/O in hearers(5, src.loc)) + O.show_message("[user.name] further abuses the shattered [src.name].") + else + if(istype(I, /obj/item/weapon) ) + var/obj/item/weapon/W = I + if(W.force <15) + for (var/mob/O in hearers(5, src.loc)) + O.show_message("[user.name] hits the [src.name] with the [W.name] with no visible effect." ) + playsound(src.loc, 'Glasshit.ogg', 100, 1) + else + src.hitstaken++ + if(src.hitstaken==3) + for (var/mob/O in hearers(5, src.loc)) + O.show_message("[user.name] smashes the [src.name]!" ) + src.isbroken=1 + playsound(src.loc, 'Glassbr3.ogg', 100, 1) + else + for (var/mob/O in hearers(5, src.loc)) + O.show_message("[user.name] forcefully slams the [src.name] with the [I.name]!" ) + playsound(src.loc, 'Glasshit.ogg', 100, 1) + else + user << "This does nothing." + src.update_icon() + +/obj/machinery/newscaster/attack_ai(mob/user as mob) + return src.attack_hand(user) //or maybe it'll have some special functions? No idea. + + +/obj/machinery/newscaster/attack_paw(mob/user as mob) + user << "The newscaster controls are far too complicated for your tiny brain!" + return + + + + + +//######################################################################################################################## +//###################################### NEWSPAPER! ###################################################################### +//######################################################################################################################## + +/obj/item/weapon/newspaper + name = "Newspaper" + desc = "An issue of The Griffon, the newspaper circulating aboard Nanotrasen Space Stations." + icon_state = "newspaper" + w_class = 2 //Let's make it fit in trashbags! + var/screen = 0 + var/pages = 0 + var/curr_page = 0 + var/list/datum/feed_channel/news_content = list() + var/datum/feed_message/important_message = null + var/scribble="" + var/scribble_page = null + +/*obj/item/weapon/newspaper/attack_hand(mob/user as mob) + ..() + world << "derp"*/ + +obj/item/weapon/newspaper/attack_self(mob/user as mob) + if(ishuman(user)) + var/mob/living/carbon/human/human_user = user + var/dat + src.pages = 0 + switch(screen) + if(0) //Cover + dat+="
The Griffon
" + dat+="
Nanotrasen-standard newspaper, for use on Nanotrasen© Space Facilities

" + if(isemptylist(src.news_content)) + if(src.important_message) + dat+="Contents:
" + else + dat+="Other than the title, the rest of the newspaper is unprinted..." + else + dat+="Contents:
" + if(scribble_page==curr_page) + dat+="
There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" + dat+= "
Next Page
Done reading
" + if(1) // X channel pages inbetween. + for(var/datum/feed_channel/NP in src.news_content) + src.pages++ //Let's get it right again. + var/datum/feed_channel/C = src.news_content[src.curr_page] + dat+="[C.channel_name] \[created by: [C.author]\]

" + if(C.censored) + dat+="This channel was deemed dangerous to the general welfare of the station and therefore marked with a D-Notice. Its contents were not transferred to the newspaper at the time of printing." + else + if(isemptylist(C.messages)) + dat+="No Feed stories stem from this channel..." + else + dat+="" + if(scribble_page==curr_page) + dat+="
There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" + dat+= "

Previous Page
Next Page
" + if(2) //Last page + for(var/datum/feed_channel/NP in src.news_content) + src.pages++ + if(src.important_message!=null) + dat+="
Wanted Issue:


" + dat+="Criminal name: [important_message.author]
" + dat+="Description: [important_message.body]" + else + dat+="Apart from some uninteresting Classified ads, there's nothing on this page..." + if(scribble_page==curr_page) + dat+="
There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" + dat+= "
Previous Page
" + else + dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" + + dat+="

[src.curr_page+1]
" + human_user << browse(dat, "window=newspaper_main;size=300x400") + onclose(human_user, "newspaper_main") + else + user << "The paper is full of intelligible symbols!" + + +obj/item/weapon/newspaper/Topic(href, href_list) + var/mob/living/U = usr + ..() + if ((src in U.contents) || ( istype(loc, /turf) && in_range(src, U) ) ) + U.machine = src + if(href_list["next_page"]) + if(curr_page==src.pages+1) + return //Don't need that at all, but anyway. + if(src.curr_page == src.pages) //We're at the middle, get to the end + src.screen = 2 + else + if(curr_page == 0) //We're at the start, get to the middle + src.screen=1 + src.curr_page++ + playsound(src.loc, "pageturn", 50, 1) + + else if(href_list["prev_page"]) + if(curr_page == 0) + return + if(curr_page == 1) + src.screen = 0 + + else + if(curr_page == src.pages+1) //we're at the end, let's go back to the middle. + src.screen = 1 + src.curr_page-- + playsound(src.loc, "pageturn", 50, 1) + + if (istype(src.loc, /mob)) + src.attack_self(src.loc) + + +obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/pen)) + if(src.scribble_page == src.curr_page) + user << "There's already a scribble in this page... You wouldn't want to make things too cluttered, would you?" + else + var/s = strip_html( input(user, "Write something", "Newspaper", "") ) + s = copytext(sanitize(s), 1, MAX_MESSAGE_LEN) + if (!s) + return + if (!in_range(src, usr) && src.loc != usr) + return + src.scribble_page = src.curr_page + src.scribble = s + src.attack_self(user) + return + + +////////////////////////////////////helper procs + + +/obj/machinery/newscaster/proc/scan_user(mob/living/carbon/human/human_user as mob) + if(human_user.wear_id) //Newscaster scans you + if(istype(human_user.wear_id, /obj/item/device/pda) ) //autorecognition, woo! + var/obj/item/device/pda/P = human_user.wear_id + if(P.id) + src.scanned_user = "[P.id.registered_name] ([P.id.assignment])" + else + src.scanned_user = "Unknown" + else if(istype(human_user.wear_id, /obj/item/weapon/card/id) ) + var/obj/item/weapon/card/id/ID = human_user.wear_id + src.scanned_user ="[ID.registered_name] ([ID.assignment])" + else + src.scanned_user ="Unknown" + else + src.scanned_user ="Unknown" + + +/obj/machinery/newscaster/proc/print_paper() + feedback_inc("newscaster_newspapers_printed",1) + var/obj/item/weapon/newspaper/NEWSPAPER = new /obj/item/weapon/newspaper + for(var/datum/feed_channel/FC in src.channel_list) + NEWSPAPER.news_content += FC + if(src.wanted_issue) + NEWSPAPER.important_message = src.wanted + NEWSPAPER.loc = get_turf(src) + src.paper_remaining-- + return + + +/obj/machinery/newscaster/proc/newsAlert(channel) + var/turf/T = get_turf(src) + if(channel) + for(var/mob/O in hearers(world.view-1, T)) + O.show_message("[src.name] beeps, \"Breaking news from [channel]!\"",2) + src.alert = 1 + src.update_icon() + spawn(600) + src.alert = 0 + src.update_icon() + else + for(var/mob/O in hearers(world.view-1, T)) + O.show_message("[src.name] beeps, \"Wanted notice posted!\"",2) + playsound(src.loc, 'twobeep.ogg', 75, 1) diff --git a/icons/mob/items_lefthand.dmi b/icons/mob/items_lefthand.dmi index e2d020fb9f1..9aa23ca974b 100644 Binary files a/icons/mob/items_lefthand.dmi and b/icons/mob/items_lefthand.dmi differ diff --git a/icons/mob/items_righthand.dmi b/icons/mob/items_righthand.dmi index d4a49d468b7..30f36441a35 100644 Binary files a/icons/mob/items_righthand.dmi and b/icons/mob/items_righthand.dmi differ diff --git a/sound/effects/hit_on_shattered_glass.ogg b/sound/effects/hit_on_shattered_glass.ogg new file mode 100644 index 00000000000..dfeca0ba629 Binary files /dev/null and b/sound/effects/hit_on_shattered_glass.ogg differ