ID:157169
 
I've been fooling around with an admin system that let's you mute some one, asks you how long you want to mute them for in minutes, and then after that time has expired, automatically unmutes them. The obvious problem here is that this can all be bypassed by logging out and logging back in. Well, I first tried creating my own custom spawn/sleep proc called Wait and using that to time them, but it doesn't work. Then I tried using spawn() but it stops counting down after the user logs back in. I'm not sure what to do. Any ideas?
oh this is a fun one, ive done these before. set up your timer like normal, but also set a var against them that if they activate the logout() proc it puts their name in a list of permanently muted players until a GM unmutes them, then they'll remember not to logout to unmute =D
In response to Dragonblix
That's what the sleep() and spawn() procs do when you use them as timers. But I don't want to permanently mute someone if they're already muted and just log out cus they want to quit playing. I thought about throwing their keys into a multi-list and having their keys associated with the time remaining in their mute in seconds, and then using my own custom proc to count down the time. Then I'd call on the proc when I wanted to mute them, and whenever they logged back in. But that's a ton of work and I don't want to start on it if there's an easier way.
In response to Gypsy
well you know you could always set up a 2nd timer when he/she logs out, ans if they reenter to soon, as indicating trying to bypass the mute. then the permamute takes effect. but there are always better solutions, thats just my take on it.
Have a mute variable containing the time it is suppose to expire at (ex: with worldtime + X). When they log out, check if the time passed yet - if not, minus the worldtime so you are left with just X.

When they log in, check if that variable is NOT 0 ( in other words, it is X). If so, add worldtime + Y (Y is a penalty time, if you so desire) to the X
A generic solution I wrote a while ago: [link]
In response to Dragonblix
I wanna script!!!!

A way with NO loops!!! CRAZY!!! Just thought of it too ^-^.

var/list/Mutes = new/list

/*This verb will take the selected player's key and add it to the Mute list
with a world up-time number followed by the inputed amount of time. And if
0 is inputed it will make the mute length a cheap INF*/

mob/verb/Mute_Player(mob/m as mob in world)
if(ismob(m) && m.key)
var/KEY = m.key
var/N = input("For how long(1 = 0.1 seconds and 0 for inf).") as num|null
if(!isnull(N))
if(N == 0)
N = 999999999999999999999999999999999999999999999999*99999999999999999999999999999999999999999999*99999999999999999999999999999999999999999
Mutes[KEY] = world.time+N

/*This verb updates the Mutes list and removes those who havn't talked yet however
are no longer muted(time expired), then allows you to select a key to be removed*/

mob/verb/UnMute_Player()
if(istype(Mutes,/list))
for(var/KEY in Mutes)
var/Muted = Mutes[KEY]
if(Muted)
if(world.time >= text2num(Muted))
var/spot = Mutes.Find(KEY)
if(spot)
Mutes = Mutes.Cut(spot,spot++)
var/Key = input("Who would you like to unmute?") as null|anything in Mutes
var/spot = Mutes.Find(Key)
if(spot)
Mutes = Mutes.Cut(spot,spot++)
else
Mutes = new/list

/*This verb will check the Mutes list for the src's key and then test
it's world up-time stamp with the end time stamp if found.*/

mob/verb/Say(t as text)
if(istype(Mutes,/list))
var/Muted = Mutes[src.key]
if(Muted)
if(world.time >= text2num(Muted))
var/spot = Mutes.Find(src.key)
if(spot)
Mutes = Mutes.Cut(spot,spot++)
else
src << "<b>Sorry, your muted."
return
world << "[src] says: [t]"
Thanks so much for your input guys! I combined all of your ideas to come up with this:

var
list
muted = list()
adminWait = list()
reported = list()
respected = list()

mob
Write(var/savefile/F)
..()

//If the user's key is in muted...
if(muted[src.ckey])
//Take the value for the key and check the make sure it's not null
var/x = text2num(muted[src.ckey])
if(x)
//Then take the value for their key and subtract the world.timeofday variable from it
var/time = x - world.timeofday
if(time > 0)
//If their punishment hasn't been served yet, write the remaining time to the "timeleft" var in their savefile
F["timeleft"] << time
else if(time <= 0)
if(muted[src.ckey])
//If it has been served, remove them (this should have already been done, but this will just be an added precaution)
//Hence why we check to see if it's still there even
muted -= src.ckey
src.mute = 0
src.SGS_locked = 0

Read(var/savefile/F)
..()
if(muted[src.ckey])
//If the user's key is in muted, load up the "timeleft" variable into the time var
var/time
F["timeleft"] >> time

//Then, change the value of their key in muted to the time that their punishment will expire
muted[src.ckey] = time + world.timeofday

mob
proc
//Run at login only
check()
//If the user's key is in muted...
if(muted[src.ckey])
//Determine the value for their key in muted
var/x = text2num(muted[src.ckey])
if(x)
//Take their value and subtract the current time to get the remaining punishment
var/time = x - world.timeofday
if(time <= 0)
//If time has been served, remove them from the list and announce it
muted -= src.ckey
world << "[server] [src.name] has been unmuted."
src.mute = 0
src.SGS_locked = 0
else if(time > 0)
src.mute = 1
//Otherwise, create a countdown (that doesn't interupt the proc) until their time has been served
spawn()
sleep(time)
world << "[server] [src.name] has been unmuted."
src.mute = 0
src.SGS_locked = 0
if(src.ckey in adminWait)
..()
if(src.ckey in reported)
..()
if(src.ckey in respected)
..()

world
New()
..()
var/savefile/F = new("world_save")

F["muted"] >> muted
F["adminWait"] >> adminWait
F["reported"] >> reported
F["respected"] >> respected

Del()
..()
var/savefile/F = new("world_save")

F["muted"] << muted
F["adminWait"] << adminWait
F["reported"] << reported
F["respected"] << respected

mob
proc
Unmute()
var/people = list()
for(var/mob/characters/M in world)
if(M.mute == 1)
people += M

people += "Cancel"

var/M = input("Who would you like to unmute?","Unmute") in people

if(M == "Cancel")
return
M:mute = 0
M:SGS_locked = 0
muted -= src.ckey
world << "<b>[M:name] has been unmute by [src.name].</b>"

Mute()
var/people = list() //Make a list of players in the world
for(var/mob/characters/M in world)
people += M

//Give the user a choice of who to mute
var/M = input("Who would you like to mute?","Mute") in people + list("Cancel")

if(M == "Cancel")
return

if(M != "Cancel") //If the choice isn't cancel and it isn't the user
//Generate the predetermined amount of time
var/time = list()
for(var/i=300,i<=1800,i+=300) //i is seconds
var/t = "[i/60]"
t += " minutes"

//Add 1 hour to the selection
if(i==1800)
var/hour = i*2
var/hourDisplay = "[hour/60] minutes"
time["[hourDisplay]"] = hour
break

//Add the final values
time["[t]"] = i

//User selects the time, or can choose their own
var/preTime = input("How long should [M:name] be muted for?","Mute") in time + list("Custom","Cancel")
var/custTime

if(preTime == "Cancel")
return

if(preTime == "Custom")
chooseTime
custTime = input("How long should [M:name] be muted for in minutes?","Mute") as num
if(custTime == 0)
src << "[server] Error. 0 is not a valid selection."
goto chooseTime

//User gives a reason why they're muting them
var/reason = input("Why are you muting [M:name]?","Mute") as text //Ask for a reason

if(preTime == "Custom")
//Announce the mute, and then value the time as the user's ckey in muted
world << "[server] [M:name] has been muted for [custTime] minutes because: [reason]"
M:mute=1
M:respectPts -= 1
muted[src.ckey] = round(custTime)*60*10 + world.timeofday
spawn()
sleep(round(custTime)*60*10)
M:mute = 0
muted -= src.ckey
world << "[server] [M:name] has been unmuted."
return

//Go through with it (only for all predetermined times)
world << "[server] [M:name] has been muted for [preTime] because: [reason]"
M:respectPts -= 1
M:mute = 1
muted[src.ckey] = time[preTime]*10 + world.timeofday
spawn()
sleep(time[preTime]*10)
M:mute = 0
muted -= src.ckey
world << "[server] [M:name] has been unmuted."


It's a little long, I know, but it works perfectly. I decided to use world.timeofday instead of just the world.time variable because I'd like to keep track of the user's punishment over the course of the Earth's time, instead of just my individual world's time. :) Once again, thanks so much for all of your help every one! Feel free to use my code if you'd like. It's the least I can do. :)

Oh and by the way, the variable server is just this:

var
server = "<b><font color=red>Server:</font></b>"
In response to Gypsy
Use realtime, not timeofday. It has limited accuracy (good job there, UNIX) but it won't roll over at midnight.