--- scripts/client.functions.old	2010-02-19 13:13:58.457935120 -0500
+++ scripts/client.functions	2010-04-17 20:12:43.609953067 -0400
@@ -295,6 +295,7 @@
 	(1,"Import deck","Ctrl+I",""),
 	('length(decks)>0',"Select deck","Ctrl+D",""),
 	(1,"Register full set...","","RegisterSubmenu()"),
+	(1,"Register full playset...","","RegisterPlaysetSubmenu()"),
 	(1,"{hr}","",""),
 	(1,"Show players online","/who",""),
 	("length(room.tables)>0","Describe tables","/tables",""),
@@ -389,6 +390,8 @@
 "Send Quit-message to all players and game servers. After that, reboot the meta server.");
 HELP{"chat"}{"register"}=("set","register complete set",NULL,
 "If the player has collected all cards of the {yellow}set{white}, he or she is awarded by a bonus. The bonus is $0.1 per individual card in the set. If the player has not yet collected all cards, the number of missing cards is announced. The {yellow}set{white} must be given as an abbreviation of the card set (case insensitive). If the abbreviation is not valid, the list of valid abbreviations are shown.");
+HELP{"chat"}{"registerplayset"}=("set","register playset",NULL,
+"If the player has already registered the {yellow}set{white}, and has collected a full playset of each card in the set, he or she is awarded by a bonus.  The bonus is $2 per distinct card in the set. If the player has not yet collected all cards, the number of missing cards is announced. The {yellow}set{white} must be given as an abbreviation of the card set (case insensitive). If the abbreviation is not valid, the list of valid abbreviations are shown.");
 HELP{"chat"}{"removeuser"}=("player","delete user",("God",),
 "This command deletes all data of {yellow}player{white}.");
 HELP{"chat"}{"reproduce"}=("","add products",("God","Salesman"),
@@ -6251,6 +6254,24 @@
   d=pop();
   m=pop();
 }
+
+#
+# RegisterPlaysetSubmenu() - Set registration menu.
+#
+def RegisterPlaysetSubmenu
+{
+  push(m);
+  push(d);
+  m=(,);
+  for(s)(sets())
+  {
+    d=set_data(s);
+    m=m+(("Register "+d[0]+" playset","/registerplayset "+s,""),);
+  }
+  Submenu("Register Playset",m);
+  d=pop();
+  m=pop();
+}
 
 #
 # CheckLegalitySubmenu() - Deck legality checking menu.
--- scripts/meta-server.functions.old	2010-04-17 20:13:41.401947386 -0400
+++ scripts/meta-server.functions	2010-04-18 04:41:00.537947182 -0400
@@ -37,9 +37,16 @@
 # REQUIRE_VERSION - version number required for client to connect
 # RTFM - help text
 # SET_BONUS_MULTIPLIER - how much each card earns when registering
-# PLAYSET_BONUS_MULTIPLIER - how much each distinct earns when registering a playset
-# PLAYSET_COUNT - number of each card required for a full playset
+# PLAYSET_BONUS_MULTIPLIER - how much each unique card earns when registering a playset
 # SILENT_SEALED_TRADE - if set, allow giving cards secretly in table in sealed mode
+# PLAYSET_COUNT - number of copies of each card required to register a playset.
+#   A value <= 0 disables playset registration.
+#   WARNING: It is not recommended to increase this number after players have
+#    already registered playsets, as they may end up with more cards for trade
+#    than should be allowed.  In fact, because of how the AvailableForSale()
+#    check is performed, in such situations the user might not be able to
+#    easily "untrade" those cards, either.
+#
 #
 # Variables:
 #
@@ -103,7 +110,8 @@
 #     3 game results total users{name}[3][3]{nmb.players}{result type}=count
 #     4 (last login time,last event time,connection from)
 #     5 player administrative info
-#     6-9 reserved
+#     6 list of registered playsets
+#     7-9 reserved
 #   4 backupdata
 #     0 - registered tournament decks 
 #           users{name}[4][0]{id}=deck content as a list of pairs (numb.of cards,card number)
@@ -181,6 +189,8 @@
 LOSER_PERCENTAGE=0.20;
 DRAW_PERCENTAGE=1.00;
 SET_BONUS_MULTIPLIER=0.5;
+PLAYSET_BONUS_MULTIPLIER=2;
+PLAYSET_COUNT=0;
 
 REQUIRE_VERSION="0.8.9";
 REQUIRE_GAME_VERSION="0.9.3";
@@ -212,6 +222,7 @@
 command.acl{"/products"}=(0,("God","Salesman","Guard","Judge","player"));
 command.acl{"/reboot"}=(0,("God",));
 command.acl{"/register"}=(1,("player",));
+command.acl{"/registerplayset"}=(1,("player",));
 command.acl{"/reload"}=(0,("God",));
 command.acl{"/removeuser"}=(1,("God",));
 command.acl{"/reproduce"}=(0,("God","Salesman"));
@@ -2055,8 +2066,11 @@
 #
 def AvailableForTrade
 {
+  push(psc);
+  psc = max(PLAYSET_COUNT-1, 0);
   check_card(ARG);
-  return(users{ARG[0]}[2]{ARG[1]}[0] > count(SetOfCard(ARG[1]),users{ARG[0]}[3][2]));
+  return(users{ARG[0]}[2]{ARG[1]}[0] > count(SetOfCard(ARG[1]),users{ARG[0]}[3][2]) + psc*count(SetOfCard(ARG[1]),users{ARG[0]}[3][6]));
+  psc=pop();
 }
 
 #
@@ -2065,8 +2079,11 @@
 #
 def AvailableForSale
 {
+  push(psc);
+  psc = max(PLAYSET_COUNT-1, 0);
   check_card(ARG[0],ARG[1]);
-  return(ARG[2] <= users{ARG[0]}[2]{ARG[1]}[0] - count(SetOfCard(ARG[1]),users{ARG[0]}[3][2]));
+  return(ARG[2] <= users{ARG[0]}[2]{ARG[1]}[0] - count(SetOfCard(ARG[1]),users{ARG[0]}[3][2]) - psc*count(SetOfCard(ARG[1]),users{ARG[0]}[3][6]));
+  psc=pop();
 }
 
 #
@@ -2455,6 +2472,8 @@
     }
     Reply(m);
     Reply("  Complete sets: "+join(users{ARG[0]}[3][2]," "));
+    if(length(users{ARG[0]}[3][6]) > 0)
+      Reply("  Complete playsets: "+join(users{ARG[0]}[3][6]," "));
     if(users{ARG[0]}[3][0]{"plan"} != NULL)
       Reply("  "+users{ARG[0]}[3][0]{"plan"});
     p=pop();
@@ -2515,6 +2534,62 @@
     Reply("Legal card set abbreviations are:"+join(forall("' {yellow}#{white} = '+set.data{#}[0]",keys("set.data")),","));
   } 
 }
+
+#
+# CommandRegisterplayset() - Implementation of the command /registerplayset.
+#
+def CommandRegisterplayset
+{
+  if(PLAYSET_COUNT <= 0)
+  {
+    Reply("{red}Playset registration is not enabled.");
+  }
+  else if(has_entry(ARG[0],set.data))
+  {
+    push(s);
+    push(n);
+    s=ARG[0];
+    n=user_has_cards(User(),forall('(' + PLAYSET_COUNT + ',#)',seq(set.data{s}[1],set.data{s}[2])));
+    if(n)
+      Reply("{blue}You still have "+n+" card(s) to collect.");
+    else
+    {
+      if(users{User()}[3][6] == NULL)
+        users{User()}[3][6] = (,);
+      if(count(s,users{User()}[3][6]))
+        Reply("{red}You have already registered a playset of "+set.data{s}[0]+".");
+      else if(!count(s,users{User()}[3][2]))
+        Reply("{red}You have not yet registered "+set.data{s}[0]+".");
+      else if(Mode()!="")
+        Reply("{red}Cannot register in "+Mode()+" mode.");
+      else
+      {
+        for(c)(seq(set.data{s}[1],set.data{s}[2]))
+        {
+          check_card(User(),c);
+          if(users{User()}[2]{c}[0] - users{User()}[2]{c}[1] < PLAYSET_COUNT)
+          {
+            SetForsale(c,users{User()}[2]{c}[0] - PLAYSET_COUNT);
+            UpdateCard(c);
+          }
+        }
+        n= set.data{s}[2] - set.data{s}[1] + 1;
+        SendAll("Message","{green}"+User()+" has collected a playset of "+set.data{s}[0]+" cards ("+ PLAYSET_COUNT*n +" total).");
+        n=n*PLAYSET_BONUS_MULTIPLIER;
+        SendAll("Message","{green}"+User()+" is awarded a bonus of $"+format("%.2f",n)+".");
+        TransferMoney(User(),n);
+        users{User()}[3][6]=users{User()}[3][6] + (s,);
+      }
+    }
+    n=pop();
+    s=pop();
+  }
+  else
+  {
+    Reply("{red}You tried to register a playset of unknown card set {yellow}"+ARG[0]);
+    Reply("Legal card set abbreviations are:"+join(forall("' {yellow}#{white} = '+set.data{#}[0]",keys("set.data")),","));
+  } 
+}
 
 #
 # CommandAddproduct() - Implementation of the command /addproduct.
--- scripts/Mtg-meta-server.include.old	2010-04-17 20:19:46.257950904 -0400
+++ scripts/Mtg-meta-server.include	2010-04-18 05:11:25.017945559 -0400
@@ -19,6 +19,12 @@
 LOSER_PERCENTAGE=0.20;
 DRAW_PERCENTAGE=0.15;
 
+# Uncomment the next line to enable playset registration.  See the comments
+# in meta-server.functions regarding changing this value after users have
+# already registered playsets (in short, don't do it).
+
+# PLAYSET_COUNT=4;
+
 ANONYMOUS_IP="www.wizards.com";
 
 if(!load("products"))
