diff --git a/code/defines/obj.dm b/code/defines/obj.dm
index db8718d435..0f09c88fc9 100644
--- a/code/defines/obj.dm
+++ b/code/defines/obj.dm
@@ -32,6 +32,14 @@
var/state = 1
//state = 1 for playing : default
//state = 2 for observing
+ var/admincaster_screen = 0 //See newscaster.dm under machinery for a full description
+ var/datum/feed_message/admincaster_feed_message = new /datum/feed_message //These two will act as holders.
+ var/datum/feed_channel/admincaster_feed_channel = new /datum/feed_channel
+ var/admincaster_signature //What you'll sign the newsfeeds as
+
+/obj/admins/New()
+ src.admincaster_signature = "Nanotrasen Officer #[rand(0,9)][rand(0,9)][rand(0,9)]"
+ ..()
/obj/effect/beam
name = "beam"
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 0978c5f906..6c4c5548b1 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -104,7 +104,7 @@ Class Procs:
/*
Big note: if do not call ..() in any machinery subtype process() call or it will
be removed from the list of machines to iterate. It is, however, okay to call ..()
- if the machine has a parent process() call. For instance, machinery/atmosphereics has a
+ if the machine has a parent process() call. For instance, machinery/atmospherics has a
root process() call, so things like cryocells can call ..() and not worry about
it getting removed from machines.
*/
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index 65685905f4..2c45e611fb 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -3,11 +3,12 @@
//###-Agouri###################################
/datum/feed_message
- var/author=""
- var/body=""
+ var/author =""
+ var/body =""
//var/parent_channel
- var/backup_body=""
- var/backup_author=""
+ var/backup_body =""
+ var/backup_author =""
+ var/is_admin_message = 0
/datum/feed_channel
var/channel_name=""
@@ -17,9 +18,31 @@
var/author=""
var/backup_author=""
var/censored=0
+ var/is_admin_channel=0
//var/page = null //For newspapers
-var/list/obj/machinery/newscaster/allCasters = list() //list that will contain reference to all newscasters in existence.
+/datum/feed_message/proc/clear()
+ src.author = ""
+ src.body = ""
+ src.backup_body = ""
+ src.backup_author = ""
+
+/datum/feed_channel/proc/clear()
+ src.channel_name = ""
+ src.messages = list()
+ src.locked = 0
+ src.author = ""
+ src.backup_author = ""
+ src.censored = 0
+ src.is_admin_channel = 0
+
+/datum/feed_network
+ var/list/datum/feed_channel/network_channels = list()
+ var/datum/feed_message/wanted_issue
+
+var/datum/feed_network/news_network = new /datum/feed_network //The global news-network, which is coincidentally a global list.
+
+var/list/obj/machinery/newscaster/allCasters = list() //Global list that will contain reference to all newscasters in existence.
/obj/machinery/newscaster
@@ -29,7 +52,8 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
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/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.
+ //OBSOLETE: We're now using a global news network
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
@@ -46,37 +70,38 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
//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
+ var/unit_no = 0 //Each newscaster has a unit number
+ //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 //OBSOLETE
// 0 = there's no WANTED issued, we don't need a special icon_state
// 1 = Guess what.
+ var/alert_delay = 500
var/alert = 0
- // 0 = there hasn't been a news/wanted update in the last minutes
+ // 0 = there hasn't been a news/wanted update in the last alert_delay
// 1 = there has
var/scanned_user = "Unknown" //Will contain the name of the person who currently uses the newscaster
- var/msg = ""; //Feed message
+ 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/c_locked=0; //Will our new channel be locked to public submissions?
+ 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
+/obj/machinery/newscaster/security_unit //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...
+/obj/machinery/newscaster/New() //Constructor, ho~
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...
+ ..() //I just realised the newscasters weren't in the global machines list. The superconstructor call will tend to that
/obj/machinery/newscaster/Del()
allCasters -= src
@@ -91,15 +116,17 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
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
+ if(news_network.wanted_issue) //wanted icon state, there can be no overlays on it as it's a priority message
icon_state = "newscaster_wanted"
return
+ if(alert) //new message alert overlay
+ src.overlays += "newscaster_alert"
+
+ if(hitstaken > 0) //Cosmetic damage overlay
+ src.overlays += image(src.icon, "crack[hitstaken]")
+
icon_state = "newscaster_normal"
return
@@ -139,7 +166,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
/obj/machinery/newscaster/attack_ai(mob/user as mob)
return src.attack_hand(user)
-/obj/machinery/newscaster/attack_hand(mob/user as mob)
+/obj/machinery/newscaster/attack_hand(mob/user as mob) //########### THE MAIN BEEF IS HERE! And in the proc below this...############
if(!src.ispowered || src.isbroken)
return
if(istype(user, /mob/living/carbon/human) || istype(user,/mob/living/silicon) )
@@ -153,7 +180,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
if(0)
dat += "Welcome to Newscasting Unit #[src.unit_no].
Interface & News networks Operational."
dat += "
Property of Nanotransen Inc"
- if(src.wanted_issue)
+ if(news_network.wanted_issue)
dat+= "
Read Wanted Issue"
dat+= "
Create Feed Channel"
dat+= "
View Feed Channels"
@@ -163,10 +190,9 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
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
+ if(news_network.wanted_issue)
+ wanted_already = 1
+
dat+="
Feed Security functions:
"
dat+="
[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue"
dat+="
Censor Feed Stories"
@@ -174,11 +200,14 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
dat+="
The newscaster recognises you as: [src.scanned_user]"
if(1)
dat+= "Station Feed Channels
"
- if( isemptylist(src.channel_list) )
+ if( isemptylist(news_network.network_channels) )
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 news_network.network_channels)
+ if(CHANNEL.is_admin_channel)
+ dat+="[CHANNEL.channel_name]
"
+ else
+ 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) )
@@ -219,30 +248,35 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
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_channels = list() //Let's get dem existing channels - OBSOLETE
var/list/existing_authors = list()
- for(var/datum/feed_channel/FC in src.channel_list)
- existing_channels += FC.channel_name
+ for(var/datum/feed_channel/FC in news_network.network_channels)
+ //existing_channels += FC.channel_name //OBSOLETE
if(FC.author == "\[REDACTED\]")
existing_authors += FC.backup_author
else
- existing_authors +=FC.author
+ 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)
+ var/check = 0
+ for(var/datum/feed_channel/FC in news_network.network_channels)
+ if(FC.channel_name == src.channel_name)
+ check = 1
+ break
+ if(check)
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/total_num=length(news_network.network_channels)
var/active_num=total_num
var/message_num=0
- for(var/datum/feed_channel/FC in src.channel_list)
+ for(var/datum/feed_channel/FC in news_network.network_channels)
if(!FC.censored)
- message_num += length(FC.messages)
+ message_num += length(FC.messages) //Dont forget, datum/feed_channel's var messages is a list of datum/feed_message
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
@@ -267,10 +301,10 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
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))
+ if(isemptylist(news_network.network_channels))
dat+="No feed channels found active...
"
else
- for(var/datum/feed_channel/CHANNEL in src.channel_list)
+ for(var/datum/feed_channel/CHANNEL in news_network.network_channels)
dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
"
dat+="
Cancel"
if(11)
@@ -278,10 +312,10 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
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))
+ if(isemptylist(news_network.network_channels))
dat+="No feed channels found active...
"
else
- for(var/datum/feed_channel/CHANNEL in src.channel_list)
+ for(var/datum/feed_channel/CHANNEL in news_network.network_channels)
dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
"
dat+="
Back"
@@ -315,17 +349,19 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
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(news_network.wanted_issue)
+ wanted_already = 1
+ end_param = 2
+
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]
"
+ if(wanted_already)
+ dat+="Wanted Issue created by: [news_network.wanted_issue.backup_author]
"
+ else
+ dat+="Wanted Issue will be created under prosecutor: [src.scanned_user]
"
dat+="
[(wanted_already) ? ("Edit Issue") : ("Submit")]"
if(wanted_already)
dat+="
Take down Issue"
@@ -346,9 +382,9 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
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+="-- STATIONWIDE WANTED ISSUE --
\[Submitted by: [news_network.wanted_issue.backup_author]\]
"
+ dat+="Criminal: [news_network.wanted_issue.author]
"
+ dat+="Description: [news_network.wanted_issue.body]
"
dat+="
Back
"
if(19)
dat+="Wanted issue for [src.channel_name] successfully edited.
"
@@ -380,7 +416,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
usr.machine = src
if(href_list["set_channel_name"])
- src.channel_name = strip_html(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""))
+ src.channel_name = strip_html_simple(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()
@@ -392,15 +428,20 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
//src.update_icon()
else if(href_list["submit_new_channel"])
- var/list/existing_channels = list()
+ //var/list/existing_channels = list() //OBSOLETE
var/list/existing_authors = list()
- for(var/datum/feed_channel/FC in src.channel_list)
- existing_channels += FC.channel_name
+ for(var/datum/feed_channel/FC in news_network.network_channels)
+ //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) )
+ var/check = 0
+ for(var/datum/feed_channel/FC in news_network.network_channels)
+ if(FC.channel_name == src.channel_name)
+ check = 1
+ break
+ if(src.channel_name == "" || src.channel_name == "\[REDACTED\]" || src.scanned_user == "Unknown" || check || (src.scanned_user in existing_authors) )
src.screen=7
else
var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel")
@@ -410,8 +451,9 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
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.
+ /*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. -OBSOLETE
+ news_network.network_channels += newChannel //Adding channel to the global network
src.screen=5
src.updateUsrDialog()
//src.update_icon()
@@ -419,7 +461,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
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)
+ for(var/datum/feed_channel/F in news_network.network_channels)
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 )
@@ -439,14 +481,13 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
newMsg.author = src.scanned_user
newMsg.body = src.msg
feedback_inc("newscaster_stories",1)
- for(var/datum/feed_channel/FC in src.channel_list)
+ for(var/datum/feed_channel/FC in news_network.network_channels)
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)
+ FC.messages += newMsg //Adding message to the network's appropriate feed_channel
+ break
+ src.screen=4
+ for(var/obj/machinery/newscaster/NEWSCASTER in allCasters)
+ NEWSCASTER.newsAlert(src.channel_name)
src.updateUsrDialog()
@@ -479,13 +520,12 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
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(news_network.wanted_issue)
+ already_wanted = 1
+
if(already_wanted)
- src.channel_name = src.wanted.author
- src.msg = src.wanted.body
+ src.channel_name = news_network.wanted_issue.author
+ src.msg = news_network.wanted_issue.body
src.screen = 14
src.updateUsrDialog()
@@ -508,31 +548,35 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
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)
+ if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below
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
+ news_network.wanted_issue = WANTED
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
+ if(news_network.wanted_issue.is_admin_message)
+ alert("The wanted issue has been distributed by a Nanotrasen higherup. You cannot edit it.","Ok")
+ return
+ news_network.wanted_issue.author = src.channel_name
+ news_network.wanted_issue.body = src.msg
+ news_network.wanted_issue.backup_author = src.scanned_user
src.screen = 19
src.updateUsrDialog()
else if(href_list["cancel_wanted"])
+ if(news_network.wanted_issue.is_admin_message)
+ alert("The wanted issue has been distributed by a Nanotrasen higherup. You cannot take it down.","Ok")
+ return
var/choice = alert("Please confirm Wanted Issue removal","Network Security Handler","Confirm","Cancel")
if(choice=="Confirm")
+ news_network.wanted_issue = null
for(var/obj/machinery/newscaster/NEWSCASTER in allCasters)
- NEWSCASTER.wanted_issue = 0
- NEWSCASTER.wanted = null
NEWSCASTER.update_icon()
src.screen=17
src.updateUsrDialog()
@@ -542,6 +586,9 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
src.updateUsrDialog()
else if(href_list["censor_channel_author"])
var/datum/feed_channel/FC = locate(href_list["censor_channel_author"])
+ if(FC.is_admin_channel)
+ alert("This channel was created by a Nanotrasen Officer. You cannot censor it.","Ok")
+ return
if(FC.author != "\[REDACTED\]")
FC.backup_author = FC.author
FC.author = "\[REDACTED\]"
@@ -551,6 +598,9 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
else if(href_list["censor_channel_story_author"])
var/datum/feed_message/MSG = locate(href_list["censor_channel_story_author"])
+ if(MSG.is_admin_message)
+ alert("This message was created by a Nanotrasen Officer. You cannot censor its author.","Ok")
+ return
if(MSG.author != "\[REDACTED\]")
MSG.backup_author = MSG.author
MSG.author = "\[REDACTED\]"
@@ -560,6 +610,9 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
else if(href_list["censor_channel_story_body"])
var/datum/feed_message/MSG = locate(href_list["censor_channel_story_body"])
+ if(MSG.is_admin_message)
+ alert("This channel was created by a Nanotrasen Officer. You cannot censor it.","Ok")
+ return
if(MSG.body != "\[REDACTED\]")
MSG.backup_body = MSG.body
MSG.body = "\[REDACTED\]"
@@ -575,6 +628,9 @@ var/list/obj/machinery/newscaster/allCasters = list() //list that will contain r
else if(href_list["toggle_d_notice"])
var/datum/feed_channel/FC = locate(href_list["toggle_d_notice"])
+ if(FC.is_admin_channel)
+ alert("This channel was created by a Nanotrasen Officer. You cannot place a D-Notice upon it.","Ok")
+ return
FC.censored = !FC.censored
src.updateUsrDialog()
@@ -827,26 +883,30 @@ obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob)
/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)
+ for(var/datum/feed_channel/FC in news_network.network_channels)
NEWSPAPER.news_content += FC
- if(src.wanted_issue)
- NEWSPAPER.important_message = src.wanted
+ if(news_network.wanted_issue)
+ NEWSPAPER.important_message = news_network.wanted_issue
NEWSPAPER.loc = get_turf(src)
src.paper_remaining--
return
+/obj/machinery/newscaster/process() //Was thinking of doing the icon update through process, but multiple iterations per second does not
+ return //bode well with a newscaster network of 10+ machines. Let's just return it, as it's added in the machines list.
-/obj/machinery/newscaster/proc/newsAlert(channel)
- var/turf/T = get_turf(src)
+/obj/machinery/newscaster/proc/newsAlert(channel) //This isn't Agouri's work, for it is ugly and vile.
+ var/turf/T = get_turf(src) //Who the fuck uses spawn(600) anyway, jesus christ
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)
+ spawn(300)
src.alert = 0
src.update_icon()
+ playsound(src.loc, 'sound/machines/twobeep.ogg', 75, 1)
else
for(var/mob/O in hearers(world.view-1, T))
- O.show_message("[src.name] beeps, \"Wanted notice posted!\"",2)
- playsound(src.loc, 'sound/machines/twobeep.ogg', 75, 1)
+ O.show_message("[src.name] beeps, \"Attention! Wanted issue distributed!\"",2)
+ playsound(src.loc, 'sound/machines/warning-buzzer.ogg', 75, 1)
+ return
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 597ae56a08..9be348c060 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -2235,6 +2235,220 @@ var/global/BSACooldown = 0
return
//hahaha
+
+ if(href_list["ac_view_wanted"]) //Admin newscaster Topic() stuff be here
+ src.admincaster_screen = 18 //The ac_ prefix before the hrefs stands for AdminCaster.
+ src.access_news_network()
+ if(href_list["ac_set_channel_name"])
+ src.admincaster_feed_channel.channel_name = strip_html_simple(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""))
+ while (findtext(src.admincaster_feed_channel.channel_name," ") == 1)
+ src.admincaster_feed_channel.channel_name = copytext(src.admincaster_feed_channel.channel_name,2,lentext(src.admincaster_feed_channel.channel_name)+1)
+ src.access_news_network()
+
+ if(href_list["ac_set_channel_lock"])
+ src.admincaster_feed_channel.locked = !src.admincaster_feed_channel.locked
+ src.access_news_network()
+
+ if(href_list["ac_submit_new_channel"])
+ var/check = 0
+ for(var/datum/feed_channel/FC in news_network.network_channels)
+ if(FC.channel_name == src.admincaster_feed_channel.channel_name)
+ check = 1
+ break
+ if(src.admincaster_feed_channel.channel_name == "" || src.admincaster_feed_channel.channel_name == "\[REDACTED\]" || check )
+ src.admincaster_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.admincaster_feed_channel.channel_name
+ newChannel.author = src.admincaster_signature
+ newChannel.locked = src.admincaster_feed_channel.locked
+ newChannel.is_admin_channel = 1
+ feedback_inc("newscaster_channels",1)
+ news_network.network_channels += newChannel //Adding channel to the global network
+ log_admin("[key_name_admin(usr)] created command feed channel: [src.admincaster_feed_channel.channel_name]!")
+ src.admincaster_screen=5
+ src.access_news_network()
+
+ if(href_list["ac_set_channel_receiving"])
+ var/list/available_channels = list()
+ for(var/datum/feed_channel/F in news_network.network_channels)
+ available_channels += F.channel_name
+ src.admincaster_feed_channel.channel_name = adminscrub(input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels )
+ src.access_news_network()
+
+ if(href_list["ac_set_new_message"])
+ src.admincaster_feed_message.body = adminscrub(input(usr, "Write your Feed story", "Network Channel Handler", ""))
+ while (findtext(src.admincaster_feed_message.body," ") == 1)
+ src.admincaster_feed_message.body = copytext(src.admincaster_feed_message.body,2,lentext(src.admincaster_feed_message.body)+1)
+ src.access_news_network()
+
+ if(href_list["ac_submit_new_message"])
+ if(src.admincaster_feed_message.body =="" || src.admincaster_feed_message.body =="\[REDACTED\]" || src.admincaster_feed_channel.channel_name == "" )
+ src.admincaster_screen = 6
+ else
+ var/datum/feed_message/newMsg = new /datum/feed_message
+ newMsg.author = src.admincaster_signature
+ newMsg.body = src.admincaster_feed_message.body
+ newMsg.is_admin_message = 1
+ feedback_inc("newscaster_stories",1)
+ for(var/datum/feed_channel/FC in news_network.network_channels)
+ if(FC.channel_name == src.admincaster_feed_channel.channel_name)
+ FC.messages += newMsg //Adding message to the network's appropriate feed_channel
+ break
+ src.admincaster_screen=4
+
+ for(var/obj/machinery/newscaster/NEWSCASTER in allCasters)
+ NEWSCASTER.newsAlert(src.admincaster_feed_channel.channel_name)
+
+ log_admin("[key_name_admin(usr)] submitted a feed story to channel: [src.admincaster_feed_channel.channel_name]!")
+ src.access_news_network()
+
+ if(href_list["ac_create_channel"])
+ src.admincaster_screen=2
+ src.access_news_network()
+
+ if(href_list["ac_create_feed_story"])
+ src.admincaster_screen=3
+ src.access_news_network()
+
+ if(href_list["ac_menu_censor_story"])
+ src.admincaster_screen=10
+ src.access_news_network()
+
+ if(href_list["ac_menu_censor_channel"])
+ src.admincaster_screen=11
+ src.access_news_network()
+
+ if(href_list["ac_menu_wanted"])
+ var/already_wanted = 0
+ if(news_network.wanted_issue)
+ already_wanted = 1
+
+ if(already_wanted)
+ src.admincaster_feed_message.author = news_network.wanted_issue.author
+ src.admincaster_feed_message.body = news_network.wanted_issue.body
+ src.admincaster_screen = 14
+ src.access_news_network()
+
+ if(href_list["ac_set_wanted_name"])
+ src.admincaster_feed_message.author = adminscrub(input(usr, "Provide the name of the Wanted person", "Network Security Handler", ""))
+ while (findtext(src.admincaster_feed_message.author," ") == 1)
+ src.admincaster_feed_message.author = copytext(admincaster_feed_message.author,2,lentext(admincaster_feed_message.author)+1)
+ src.access_news_network()
+
+ if(href_list["ac_set_wanted_desc"])
+ src.admincaster_feed_message.body = adminscrub(input(usr, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler", ""))
+ while (findtext(src.admincaster_feed_message.body," ") == 1)
+ src.admincaster_feed_message.body = copytext(src.admincaster_feed_message.body,2,lentext(src.admincaster_feed_message.body)+1)
+ src.access_news_network()
+
+ if(href_list["ac_submit_wanted"])
+ var/input_param = text2num(href_list["ac_submit_wanted"])
+ if(src.admincaster_feed_message.author == "" || src.admincaster_feed_message.body == "")
+ src.admincaster_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) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below
+ var/datum/feed_message/WANTED = new /datum/feed_message
+ WANTED.author = src.admincaster_feed_message.author //Wanted name
+ WANTED.body = src.admincaster_feed_message.body //Wanted desc
+ WANTED.backup_author = src.admincaster_signature //Submitted by
+ WANTED.is_admin_message = 1
+ news_network.wanted_issue = WANTED
+ for(var/obj/machinery/newscaster/NEWSCASTER in allCasters)
+ NEWSCASTER.newsAlert()
+ NEWSCASTER.update_icon()
+ src.admincaster_screen = 15
+ else
+ news_network.wanted_issue.author = src.admincaster_feed_message.author
+ news_network.wanted_issue.body = src.admincaster_feed_message.body
+ news_network.wanted_issue.backup_author = src.admincaster_feed_message.backup_author
+ src.admincaster_screen = 19
+ log_admin("[key_name_admin(usr)] issued a Station-wide Wanted Notification for [src.admincaster_feed_message.author]!")
+ src.access_news_network()
+
+ if(href_list["ac_cancel_wanted"])
+ var/choice = alert("Please confirm Wanted Issue removal","Network Security Handler","Confirm","Cancel")
+ if(choice=="Confirm")
+ news_network.wanted_issue = null
+ for(var/obj/machinery/newscaster/NEWSCASTER in allCasters)
+ NEWSCASTER.update_icon()
+ src.admincaster_screen=17
+ src.access_news_network()
+
+ if(href_list["ac_censor_channel_author"])
+ var/datum/feed_channel/FC = locate(href_list["ac_censor_channel_author"])
+ if(FC.author != "\[REDACTED\]")
+ FC.backup_author = FC.author
+ FC.author = "\[REDACTED\]"
+ else
+ FC.author = FC.backup_author
+ src.access_news_network()
+
+ if(href_list["ac_censor_channel_story_author"])
+ var/datum/feed_message/MSG = locate(href_list["ac_censor_channel_story_author"])
+ if(MSG.author != "\[REDACTED\]")
+ MSG.backup_author = MSG.author
+ MSG.author = "\[REDACTED\]"
+ else
+ MSG.author = MSG.backup_author
+ src.access_news_network()
+
+ if(href_list["ac_censor_channel_story_body"])
+ var/datum/feed_message/MSG = locate(href_list["ac_censor_channel_story_body"])
+ if(MSG.body != "\[REDACTED\]")
+ MSG.backup_body = MSG.body
+ MSG.body = "\[REDACTED\]"
+ else
+ MSG.body = MSG.backup_body
+ src.access_news_network()
+
+ if(href_list["ac_pick_d_notice"])
+ var/datum/feed_channel/FC = locate(href_list["ac_pick_d_notice"])
+ src.admincaster_feed_channel = FC
+ src.admincaster_screen=13
+ src.access_news_network()
+
+ if(href_list["ac_toggle_d_notice"])
+ var/datum/feed_channel/FC = locate(href_list["ac_toggle_d_notice"])
+ FC.censored = !FC.censored
+ src.access_news_network()
+
+ if(href_list["ac_view"])
+ src.admincaster_screen=1
+ src.access_news_network()
+
+ if(href_list["ac_setScreen"]) //Brings us to the main menu and resets all fields~
+ src.admincaster_screen = text2num(href_list["ac_setScreen"])
+ if (src.admincaster_screen == 0)
+ if(src.admincaster_feed_channel)
+ src.admincaster_feed_channel = new /datum/feed_channel
+ if(src.admincaster_feed_message)
+ src.admincaster_feed_message = new /datum/feed_message
+ src.access_news_network()
+
+ if(href_list["ac_show_channel"])
+ var/datum/feed_channel/FC = locate(href_list["ac_show_channel"])
+ src.admincaster_feed_channel = FC
+ src.admincaster_screen = 9
+ src.access_news_network()
+
+ if(href_list["ac_pick_censor_channel"])
+ var/datum/feed_channel/FC = locate(href_list["ac_pick_censor_channel"])
+ src.admincaster_feed_channel = FC
+ src.admincaster_screen = 12
+ src.access_news_network()
+
+ if(href_list["ac_refresh"])
+ src.access_news_network()
+
+ if(href_list["ac_set_signature"])
+ src.admincaster_signature = adminscrub(input(usr, "Provide your desired signature", "Network Identity Handler", ""))
+ src.access_news_network()
+
///////////////////////////////////////////////////////////////////////////////////////////////Panels
/obj/admins/proc/show_player_panel(var/mob/M in mob_list)
@@ -2375,6 +2589,198 @@ var/global/BSACooldown = 0
feedback_add_details("admin_verb","SPP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+/obj/admins/proc/access_news_network() //MARKER
+ set category = "Fun"
+ set name = "Access Newscaster Network"
+ set desc = "Allows you to view, add and edit news feeds."
+
+ if (!istype(src,/obj/admins))
+ src = usr.client.holder
+ if (!istype(src,/obj/admins))
+ usr << "Error: you are not an admin!"
+ return
+ var/dat
+ dat = text("Admin NewscasterAdmin Newscaster Unit
")
+
+ switch(admincaster_screen)
+ if(0)
+ dat += "Welcome to the admin newscaster.
Here you can add, edit and censor every newspiece on the network."
+ dat += "
Feed channels and stories entered through here will be uneditable and handled as official news by the rest of the units."
+ dat += "
Note that this panel allows full freedom over the news network, there are no constrictions except the few basic ones. Don't break things!"
+ if(news_network.wanted_issue)
+ dat+= "
Read Wanted Issue"
+ dat+= "
Create Feed Channel"
+ dat+= "
View Feed Channels"
+ dat+= "
Submit new Feed story"
+ dat+= "
Exit"
+ var/wanted_already = 0
+ if(news_network.wanted_issue)
+ wanted_already = 1
+ dat+="
Feed Security functions:
"
+ dat+="
[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue"
+ dat+="
Censor Feed Stories"
+ dat+="
Mark Feed Channel with Nanotrasen D-Notice (disables and locks the channel."
+ dat+="
The newscaster recognises you as:
[src.admincaster_signature]"
+ if(1)
+ dat+= "Station Feed Channels
"
+ if( isemptylist(news_network.network_channels) )
+ dat+="No active channels found..."
+ else
+ for(var/datum/feed_channel/CHANNEL in news_network.network_channels)
+ if(CHANNEL.is_admin_channel)
+ dat+="[CHANNEL.channel_name]
"
+ else
+ dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
"
+ dat+="
Refresh"
+ dat+="
Back"
+ if(2)
+ dat+="Creating new Feed Channel..."
+ dat+="
Channel Name: [src.admincaster_feed_channel.channel_name]
"
+ dat+="Channel Author: [src.admincaster_signature]
"
+ dat+="Will Accept Public Feeds: [(src.admincaster_feed_channel.locked) ? ("NO") : ("YES")]
"
+ dat+="
Submit
Cancel
"
+ if(3)
+ dat+="Creating new Feed Message..."
+ dat+="
Receiving Channel: [src.admincaster_feed_channel.channel_name]
" //MARK
+ dat+="Message Author: [src.admincaster_signature]
"
+ dat+="Message Body: [src.admincaster_feed_message.body]
"
+ dat+="
Submit
Cancel
"
+ if(4)
+ dat+="Feed story successfully submitted to [src.admincaster_feed_channel.channel_name].
"
+ dat+="
Return
"
+ if(5)
+ dat+="Feed Channel [src.admincaster_feed_channel.channel_name] created successfully.
"
+ dat+="
Return
"
+ if(6)
+ dat+="ERROR: Could not submit Feed story to Network.
"
+ if(src.admincaster_feed_channel.channel_name=="")
+ dat+="•Invalid receiving channel name.
"
+ if(src.admincaster_feed_message.body == "" || src.admincaster_feed_message.body == "\[REDACTED\]")
+ dat+="•Invalid message body.
"
+ dat+="
Return
"
+ if(7)
+ dat+="ERROR: Could not submit Feed Channel to Network.
"
+ if(src.admincaster_feed_channel.channel_name =="" || src.admincaster_feed_channel.channel_name == "\[REDACTED\]")
+ dat+="•Invalid channel name.
"
+ var/check = 0
+ for(var/datum/feed_channel/FC in news_network.network_channels)
+ if(FC.channel_name == src.admincaster_feed_channel.channel_name)
+ check = 1
+ break
+ if(check)
+ dat+="•Channel name already in use.
"
+ dat+="
Return
"
+ if(9)
+ dat+="[src.admincaster_feed_channel.channel_name]: \[created by: [src.admincaster_feed_channel.author]\]
"
+ if(src.admincaster_feed_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.admincaster_feed_channel.messages) )
+ dat+="No feed messages found in channel...
"
+ else
+ for(var/datum/feed_message/MESSAGE in src.admincaster_feed_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(news_network.network_channels))
+ dat+="No feed channels found active...
"
+ else
+ for(var/datum/feed_channel/CHANNEL in news_network.network_channels)
+ 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(news_network.network_channels))
+ dat+="No feed channels found active...
"
+ else
+ for(var/datum/feed_channel/CHANNEL in news_network.network_channels)
+ dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
"
+
+ dat+="
Back"
+ if(12)
+ dat+="[src.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_channel.author] \]
"
+ dat+="[(src.admincaster_feed_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
"
+
+ if( isemptylist(src.admincaster_feed_channel.messages) )
+ dat+="No feed messages found in channel...
"
+ else
+ for(var/datum/feed_message/MESSAGE in src.admincaster_feed_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.admincaster_feed_channel.channel_name]: \[ created by: [src.admincaster_feed_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.admincaster_feed_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.admincaster_feed_channel.messages) )
+ dat+="No feed messages found in channel...
"
+ else
+ for(var/datum/feed_message/MESSAGE in src.admincaster_feed_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
+ if(news_network.wanted_issue)
+ wanted_already = 1
+ end_param = 2
+ if(wanted_already)
+ dat+="
A wanted issue is already in Feed Circulation. You can edit or cancel it below."
+ dat+="
"
+ dat+="Criminal Name: [src.admincaster_feed_message.author]
"
+ dat+="Description: [src.admincaster_feed_message.body]
"
+ if(wanted_already)
+ dat+="Wanted Issue created by: [news_network.wanted_issue.backup_author]
"
+ else
+ dat+="Wanted Issue will be created under prosecutor: [src.admincaster_signature]
"
+ dat+="
[(wanted_already) ? ("Edit Issue") : ("Submit")]"
+ if(wanted_already)
+ dat+="
Take down Issue"
+ dat+="
Cancel"
+ if(15)
+ dat+="Wanted issue for [src.admincaster_feed_message.author] is now in Network Circulation.
"
+ dat+="
Return
"
+ if(16)
+ dat+="ERROR: Wanted Issue rejected by Network.
"
+ if(src.admincaster_feed_message.author =="" || src.admincaster_feed_message.author == "\[REDACTED\]")
+ dat+="•Invalid name for person wanted.
"
+ if(src.admincaster_feed_message.body == "" || src.admincaster_feed_message.body == "\[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: [news_network.wanted_issue.backup_author]\]
"
+ dat+="Criminal: [news_network.wanted_issue.author]
"
+ dat+="Description: [news_network.wanted_issue.body]
"
+ dat+="
Back
"
+ if(19)
+ dat+="Wanted issue for [src.admincaster_feed_message.author] successfully edited.
"
+ dat+="
Return
"
+ else
+ dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com"
+
+ //world << "Channelname: [src.admincaster_feed_channel.channel_name] [src.admincaster_feed_channel.author]"
+ //world << "Msg: [src.admincaster_feed_message.author] [src.admincaster_feed_message.body]"
+ usr << browse(dat, "window=admincaster_main;size=400x600")
+ onclose(usr, "admincaster_main")
+
+
/obj/admins/proc/Jobbans()
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 1517d53705..c0b1264630 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -199,6 +199,7 @@
verbs += /obj/admins/proc/adrev //toggle admin revives
verbs += /obj/admins/proc/adspawn //toggle admin item spawning
verbs += /client/proc/debug_variables
+ verbs += /obj/admins/proc/access_news_network //Admin access to the newscaster network
verbs += /client/proc/cmd_modify_ticker_variables
verbs += /client/proc/Debug2 //debug toggle switch
verbs += /client/proc/toggle_view_range
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 733e6728fa..083908dbcf 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -229,6 +229,8 @@ proc/cmd_admin_mute(mob/M as mob, mute_type, automute = 0)
message_admins("\blue [key_name_admin(usr)] spawned a xeno.", 1)
return
+
+
//I use this proc for respawn character too. /N
/proc/create_xeno(mob/dead/observer/G)
var/alien_caste = alert(src, "Please choose which caste to spawn.",,"Hunter","Sentinel","Drone")
diff --git a/html/changelog.html b/html/changelog.html
index 116c6dafc1..ef115bb670 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -48,6 +48,16 @@ Stuff which is in development and not yet visible to players or just code relate
should be listed in the changelog upon commit tho. Thanks. -->
+
+
+
31 August
+
Agouri updated:
+
+ - Overhauled newscasters. No visual additions but the thing is much more robust and everything works as intended. Wanted issues are fixed. Admins, check out Access News Network under Fun.
+
+
+
+
30 August 2012
Giacom updated: