@@ @@ Sanctions - an administrative system for sanctioning problem players @@ @@ By Trispis@M*U*S*H @@ All statements below reflect only Trispis's positions and should @@ not be construed as reflecting the positions of M*U*S*H or @@ its other administrators. @@ @@ INTRODUCTION @@ @@ This code is very much alpha. @@ What does this mean? @@ @@ It means: don't harass me about the pathetic code it contains. @@ @@ It means: If you can improve the code, please do. @@ @@ When I wrote this, I did so specifically for functionality on M*U*S*H. @@ I am well aware that the code is bloated in a few places; I simply made @@ it work, and walked away. I have never taken a second look at it. @@ @@ PHILOSOPHY @@ The specific purpose of this code is to provide consistency across the @@ ranks of your admin team. If you've ever had a player complain about @@ the unfairness of some punishment, when compared to the punishment a @@ different admin gave to a different player in a different, but similar, @@ situation... then you should have an appreciation for what this code is @@ intended to do. @@ @@ If one or more of your admin are considered to be meaner/nicer or @@ more/less agressive than others, this system provides total anonymity @@ for applying punishments. @@ @@ Furthermore, it is highly recommended that you spend a few @@ minutes/days/weeks, depending on your game's needs, acquainting yourself @@ and your staff with this system's capabilities and, MOST IMPORTANTLY, @@ creating a concensus on how this system is, and is not, to be used. @@ @@ Some specific recommendations I make to anyone who decides to implement @@ this system are: @@ @@ Unless the sanctity of your game's db or server is at stake, make every @@ attempt to apply these sanctions in a *consistent* order, by *always* @@ giving every player *at least* ONE +sanction1 (all of your players, new @@ or old, need to know that you have policies, where they are, and that @@ you intend to enforce them via this +sanction system) before proceeding @@ to higher sanctions. Do not *ever* "skip" to a higher sanction unless @@ your game is actually in some sort of technical or physical jeopardy. @@ And, always use the sanction system *in place of* twink-negotiation @@ (i.e., don't allow your admins to attempt to interpret or justify your @@ AUP -- simply apply the sanctions and let your game's head wiz be the @@ final arbiter). Finally, always log any incidents which result in @@ sanctions, and make a bulletin board post to your admin's bulletin @@ board group explaining the circumstances and the reasons for your use @@ of your chosen sanction. @@ @@ When Judge Roy Bean, aka The Hanging Judge, was asked if the extremely @@ low crime rate in his jurisdiction was due to the severity of his @@ punishments, he replied (paraphrase) "It's not the severity of the @@ punishment that deters crime, it's the certainty of it." @@ @@ Simple Example: @@ @@ Joe_Newbie logs in, creates a Sherman Tank, and begins killing everyone @@ he sees, friend or foe. @@ @@ Jane_Admin witnesses this event. @@ Jane_Admin uses +sanction1 on Joe_Newbie. @@ Joe settles down. @@ Jane logs and posts her account of the event. @@ @@ A week later, Joe_Newbie returns and begins harassing players verbally @@ because they're not helping him code his new bazooka. @@ @@ Bill_Admin witnesses this event. @@ Bill_Admin reviews Joe's sanctions with +sfinger. @@ Bill, at this time, should use +sanction2. @@ @@ (Joe has had a chance to review your policies. It's no one's fault but @@ his, if he didn't.) @@ @@ If Joe's repeat offenses tend to be mild, it is acceptible to give @@ extra +sanction2's. Especially if his behavior is showing improvement. @@ (You're actually making a better player of him.) @@ @@ If, OTOH, Joe shows no sign of relenting in his disruptive behavior, @@ progression to higher level sanctions... even @sitelock... may be @@ necessary. @@ @@ DEPENDENCIES @@ This code, as it is presently written, is dependent upon a few other @@ pennmush/M*U*S*H things. You will likely need to either redesign this @@ code to apply to your game's theme and/or features, or add the following @@ pieces to your game. @@ @@ 1. NO_CHAT flag (prevent players from using any of your chat system). @@ This is available as a user-contributed patch in ftp.pennmush.org @@ (/pub/PennMUSH/Source/contrib/no_chat). @@ 2. A common channel lock, to which your "highly public channels" are @@ locked. @@ 3. &CRON_HOURLY needs to be triggered hourly, without fail. @@ @@ INSTALLATION @@ @@ #2 is assumed to be your Master Room. @@ @@ &IS_WIZ (for the uselock) is assumed to include WIZARD and ROYALTY @@ players. @@ @@ When the installation is completed, the object should be owned by your @@ game's head wiz. The purpose for this is to make sure that any admin @@ name displayed in its @mail messages will be that of your head wiz, and @@ only your head wiz. Thus, all sanctions appear to come from your head @@ wiz, preventing players from knowing which admin applied the sanction. @@ @@ #100 is assumed to be your headwiz @@ @@ #200 is assumed to be your "public channels" lock object, and @@ GAGGED.PLAYERS is assumed to be the attribute thereon which contains @@ #dbrefs of players who are prevented from using those channels. @@ @@ You will need to create a restricted attribute named SANCTIONS, via the @@ @attrib command. It should be mortal_dark, wizard-only, non-inheritable, @@ nocommand, non-cloneable. @@ @@ LICENSE @@ My preference would be a combination of GPL and Artistic License, for @@ the simple reason that I'd like to have quality patches, rewrites, or @@ other improvements responsibly submitted to me. Nonetheless, I'm @@ releasing this to Public Domain, because I believe it can provide a @@ means by which games can implement player environment controls in a @@ manner which is both: a) consistent across your admin population, @@ considering their distinct styles and personalities, and b) an extremely @@ fair system, if applied with consistency. @@ @@ WARRANTY @@ No such animal. Use at your own risk. @@ @@ SUPPORT @@ No such animal. Use at your own risk. @@ @create Sanctions @link Sanctions = #2 @lock/Use Sanctions=IS_WIZ/1 &IS_WIZ Sanctions=[orflags(%#,Wr)] @set Sanctions/IS_WIZ=no_command @set Sanctions = WIZARD @set Sanctions = SAFE @set Sanctions = !NO_COMMAND &2.TR.IMPLEMENT.SANCTION Sanctions=@@ 9=%0, 8=recip-list, 7=mailmsg, 6=secs, 5=reason, 4=duration, 3=level, 2=type, 1=admin 0=player @@;@dol [setr(8,[setr(0,first(setr(9,escape(%0)),:))] [setr(1,elements(%q9,2,:))] [remove(#100,%q1)])][cemit(admin,SANCTION: [name(%q1)] has sanctioned [name(%q0)]: [switch([setr(2,elements(%q9,4,:))][setq(3,right(%q9,1))][setq(4,elements(%q9,5,:))],w,Warning,[switch(%q2,c,ChanGag,n,NO_CHAT,GAGGED)][switch(%q3,2,%bfor %q4 hours,%bindefinitely)])])][setq(5,elements(%q9,lnum(6,dec(words(%q9,:)))))][setq(6,elements(%q9,3,:))][set(%q0,sanctions:[if(hasattrval(%q0,sanctions),[xget(%q0,sanctions)]|)][rest(%q9,:)])][switch(%q2,c,[set(#200,gagged.players:[get(#200/gagged.players)] %q0)],n,[set(%q0,NO_CHAT)],g,[set(%q0,GAGGED)])][if(gt(%q3,1),set(%q0,suspect))][switch(%q3,2,set(me,list.sanction2:[v(list.sanction2)] %q0:[words(get(%q0/sanctions),|)]))]=@mail ##=Automated Sanction/[setr(7,[u(msg.sanction.%q3.[ifelse(strmatch(##,%q0),player,admin)],%q0,%q5,%q2,%q4,%q6)])][if(t(member(#100,##)),%r\%q9 == \escape\(\%0\) == %q9 %r\%q8 == %q8 %r\%q7 == %q7 %r\%q6 == %q6 %r\%q5 == %q5 %r\%q4 == %q4 %r\%q3 == %q3 %r\%q2 == %q2 %r\%q1 == %q1 %r\%q0 == %q0)][pemit(##,%r%r%q7%r%r[switch(##:%q2:%q3,%q0:g:2,Note: You have received a copy of this in @mail\, which you may read at the expiration of your %q4 hours.%r)])] @set Sanctions/2.TR.IMPLEMENT.SANCTION=no_command &CMD.SANCTION Sanctions=$+sanction *:@@ Unfinished. Need to doublecheck element grabbing. @@;@pemit %#=[switch(setr(0,pmatch(%0)),#-1,No such player as '%0'.,#-2,I don't know which '%0' you mean.,[setq(1,last(get(%q0/sanctions),|))]%r[switch(words(%q1),0,[name(%q0)] has no sanctions on record.%r%rRecommendation: +sanction1 =%r,Player: [name(%q0)]%rLatest Sanction Level: [setr(2,right(%q1,1))]%rLatest Sanction Type: [elements(%q1,3,:)] [switch(%q2,2,\(Duration: [elements(%q1,4,:)] hours\))]%rLatest Sanction Reason: [elements(%q1,lnum(5,dec(words(%q1,:))),:)]%r%rRecommendation: +sanction[ifelse(eq(%q2,4),4,inc(%q2))][switch(%q2,1,/,2,/)] [name(%q0)][switch(%q2,1,\[/24-72\])]=%r[if(gte(%q2,3),%r... and be prepared to @sitelock [name(%q0)]'s &lastsite.)][switch(%q2,4,%r%rSee Also: ANEWS SANCTIONS5)])])] &CMD.SANCTION1 Sanctions=$+sanction1 *=*:@switch [setq(0,[setr(2,pmatch(%0))]:%#:[secs()]:[setr(1,w)]:[setr(3,0)]:[setr(4,ifelse(gte(words(%1),2),%1,#-reason))]:1)][strmatch(%q0,*#-*)]=1,{@@return errors & suggestions@@;@pemit %#=%rCorrect syntax: +sanction1 =%r%rInvalid input: +sanction1 [switch(%q2,#-*,<[ansi(h,ERROR)]>,%0)]=[switch(%q4,*#-*,<[ansi(h,ERROR)]>,%q4)]%r%r[iter(graball(%q0,*#-*,:),[switch(##,#-1*,Invalid player: [u(me/msg.pmatch1,%0)],#-2*,Invalid player: [u(me/msg.pmatch2,%0)],Invalid reason: Minimum 2 words. Can't contain "#-".)],:,%r)]%r%rRecommendation: +sanction1 [switch(%q2,#-*,<[ansi(h,Name)]>,[name(%q2)])]=[switch(%q4,*#-*,<[ansi(h,Min. 2 words\, no "#-")]>,%q4)]%rNo action performed.[switch(%#,#100,%r%q0)]},{@@do action@@;@tr me/tr.implement.sanction=%q0} &CMD.SANCTION2 Sanctions=$+sanction2/* *=*:@switch [setq(0,[setr(2,pmatch(before(%1,/)))]:%#:[secs()]:[setr(1,ifelse(t(words(graball(changag channel nochat no_chat gagged,%0*))),left(%0,1),#-type))]:[setr(3,switch(after(%1,/),*d,mul(24,ifelse(trunc(#$),trunc(#$),1)),*h,ifelse(trunc(#$),trunc(#$),24),ifelse(isnum(#$),ifelse(gt(#$,0),#$,24),#-time)))]:[setr(4,ifelse(gte(words(%2),2),%2,#-reason))]:2)][strmatch(first(%q0),*#-*)]=1,{@@return errors & suggestions@@;@pemit %#=%rCorrect syntax: +sanction2/ \[/