Advertisement
Guest User

ChainedQuickStack.cs #2

a guest
May 17th, 2014
266
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 12.95 KB | None | 0 0
  1. ///ChainedQuickStack.cs for TerraMod
  2. // quick stack chained chests.
  3. // chests which placed horizontally without gap consider as CHAINED.
  4. // RuleChest
  5. //   name one of chained chest to @<PlayerName> to specify rule of inventory items protection.
  6. //   specified items in inventory will keep Item#maxStack
  7. //   if you want specify number of stacks, name #<PlayerName>
  8.  
  9.  
  10. using System;
  11. using System.Collections.Generic;
  12. using Terraria;
  13. public class ChainedQuickStack {
  14.  
  15.     static void print(string s) {
  16.         Main.NewText(s);
  17.     }
  18.     public static int log_level = 0;
  19.     static void dprint(int level, string s) {
  20.         if(log_level >= level) print(s);
  21.     }
  22.  
  23.     public class RuleChest {
  24.         const char PREFIX_MAX_STACK = '@';
  25.         const char PREFIX_N_STACK   = '#';
  26.         static bool mode_n_stack = false;
  27.         private static List<Item> items     = new List<Item>();
  28.         private static List<int>  n_stacks  = new List<int>();
  29.         private static List<int>  n_possess = new List<int>();
  30.  
  31.         public static bool isRuleChest(Chest c) {
  32.             return (c.name != string.Empty && (c.name[0] == PREFIX_MAX_STACK || c.name[0] == PREFIX_N_STACK));
  33.         }
  34.         public static bool isPrivateRuleChest(Chest c) {
  35.             string pn = Main.player[Main.myPlayer].name;
  36.             return isRuleChest(c) && string.Compare(c.name, 1, pn, 0, pn.Length, true)==0;
  37.         }
  38.         public static void readRuleAndInit(Chest c) {
  39.             if(c == null) {
  40.                 print("??? c==null");
  41.                 return;
  42.             }
  43.             if(items.Count != 0) {
  44.                 print("only one RuleChest is allowed.");
  45.                 return;
  46.             }
  47.             mode_n_stack = (c.name[0] == PREFIX_N_STACK);
  48.             foreach(Item i in c.item) {
  49.                 if(i.type <= 0) continue;//empty slot?
  50.                 //find same Item
  51.                 int add_to = -1;
  52.                 for(int x = 0; x < items.Count; x++) {
  53.                     if(items[x].IsTheSameAs(i)) {
  54.                         add_to = x;
  55.                         break;
  56.                     }
  57.                 }
  58.                 if(add_to == -1) {// first type
  59.                     items.Add(i);
  60.                     n_stacks.Add(mode_n_stack ? i.stack : i.maxStack);
  61.                 } else { // type already added
  62.                     if(mode_n_stack) {
  63.                         n_stacks[add_to] += i.stack;
  64.                     }
  65.                 }
  66.             }
  67.             //count protected item in inventory
  68.             foreach(Item i in items) {
  69.                 int np = 0;
  70.                 foreach(Item j in Main.player[Main.myPlayer].inventory) {
  71.                     if(j.type <= 0) continue;
  72.                     if(j.IsTheSameAs(i)) {
  73.                         np += j.stack;
  74.                     }
  75.                 }
  76.                 n_possess.Add(np);
  77.             }
  78.         }
  79.  
  80.         public static bool needProtect() {
  81.             return items.Count != 0;
  82.         }
  83.         public static bool needRefill() {
  84.             for(int i = 0; i < items.Count; i++) {
  85.                 if(n_possess[i] < items[i].maxStack) return true;
  86.             }
  87.             return false;
  88.         }
  89.         public static int findProtectedItem(Item si) {
  90.             for(int i = 0; i < items.Count; i++) {
  91.                 if(items[i].IsTheSameAs(si)) return i;
  92.             }
  93.             return -1;
  94.         }
  95.         public static int getDiffToMove(int i) {
  96.             if(i < 0 || i >= n_possess.Count || i >= n_stacks.Count) {
  97.                 print("??? getDiffToMove() invalid i=" + i);
  98.                 return 0;
  99.             }
  100.             return n_possess[i] - n_stacks[i];
  101.         }
  102.         public static void itemMoved(int i, int dm) {
  103.             if(i < 0 || i >= n_possess.Count) {
  104.                 print("??? itemMoved() invalid i=" + i);
  105.                 return;
  106.             }
  107.             n_possess[i] -= dm;
  108.         }
  109.  
  110.         public static void test() {
  111.             log_level = 1;
  112.             chainQuickStack(Main.player[Main.myPlayer].chest, false);
  113.             //Chest c = Main.chest[Main.player[Main.myPlayer].chest];
  114.             //print(Main.player[Main.myPlayer].name);
  115.             //print("isProtectChest()=" +isProtectChest(c));
  116.             //readRuleAndInit(c);
  117.             //print("mns=" + mode_n_stack);
  118.             //print("items.Count=" + items.Count);
  119.             //print("n_possess.Count=" + n_possess.Count);
  120.             //for(int i=0;i<items.Count;i++){
  121.             //  print(string.Format("{0,2}:{1,3}:{2,3}:{3}", i, n_stacks[i], n_possess[i], items[i].name));
  122.             //}
  123.         }
  124.     }
  125.  
  126.  
  127.     public static Chest getChestFromIndex(int i) {
  128.         if(i <= -4 || i >= Main.chest.Length) return null;
  129.         if(i == -1) return null;
  130.         if(i == -2) return Main.player[Main.myPlayer].bank;
  131.         if(i == -3) return Main.player[Main.myPlayer].bank2;
  132.         return Main.chest[i];
  133.     }
  134.  
  135.     public static void uniteInventory() {
  136.         Item[] inv = Main.player[Main.myPlayer].inventory;
  137.         Item[] items = new Item[50 + 4];//10*5+ 4(ammo), dont process coins
  138.         Array.Copy(inv, 54, items, 0, 4); // process ammo first.
  139.         Array.Copy(inv, 0, items, 4, 50);// hotbar and rest
  140.         dprint(1, "using shifted items[] : Ammo-Hotbar-rest");
  141.         for(int i = 0; i < items.Length - 1; i++) {// no need to process last one
  142.             if(items[i].type <= 0) continue;//empty slot
  143.             if(items[i].stack == items[i].maxStack) continue; // max stacked
  144.             dprint(1, string.Format("Unite slot {0}, {1}", i, items[i].ToString()));
  145.             for(int j = items.Length - 1; j >= i + 1; j--) { // find from tail
  146.                 if(items[j].type <= 0) continue;//empty slot
  147.                 if(!items[i].IsTheSameAs(items[j])) continue;//cannot use IsNotTheSameAs() which checks item.stack...
  148.                 int n_move = items[j].stack;
  149.                 if(items[i].stack + n_move > items[i].maxStack) {
  150.                     n_move = items[i].maxStack - items[i].stack;
  151.                 }
  152.                 dprint(1, string.Format("  moved from slot {0}, n_move={1}", j, n_move));
  153.                 items[i].stack += n_move;
  154.                 items[j].stack -= n_move;
  155.                 if(items[j].stack == 0) {
  156.                     items[j].SetDefaults(0, false);
  157.                 }
  158.                 if(items[i].stack == items[i].maxStack) break;// stack to max
  159.             }
  160.         }
  161.     }
  162.  
  163.     public static ChainQuickStackResult quickStack(int chest_index) {
  164.         if(chest_index == -1 || chest_index <= -4) {
  165.             print("Invalid chest_index=" + chest_index);
  166.             return null;
  167.         }
  168.         if(RuleChest.isRuleChest(getChestFromIndex(chest_index))) {
  169.             dprint(1, "ignore ProtectRuleChest");
  170.             return null;
  171.         }
  172.         Item[] item = getChestFromIndex(chest_index).item; //chest items
  173.         Item[] inv = Main.player[Main.myPlayer].inventory;//inventory items
  174.  
  175.         Main.MoveCoins(inv, item);//cannot detect move or not
  176.  
  177.         bool need_protect = RuleChest.needProtect();
  178.  
  179.         int pushed_slots = 0;
  180.         int pushed_quantity = 0;
  181.         for(int index2 = 0; index2 < Chest.maxItems; ++index2)// chest loop
  182.         {
  183.             Item ci = item[index2]; //chest item
  184.             if(ci.type <= 0 || ci.stack >= ci.maxStack) continue;//empty or max stacked
  185.             for(int index3 = 57; index3 >= 0; --index3) { // scan inventory reverse to protect left-top items
  186.                 Item si = inv[index3]; //source item
  187.                 if(!ci.IsTheSameAs(si)) continue;
  188.                 int pi = need_protect ? RuleChest.findProtectedItem(si) : -1;//process ProtectedChest if(pi!=-1)
  189.                 int dm = 0; //d-move
  190.                 dprint(1, "pi = " + pi);
  191.                 if(pi != -1) {
  192.                     dm = RuleChest.getDiffToMove(pi);
  193.                     if(dm <= 0) {
  194.                         dprint(1, "dm<=0, through " + si.ToString());
  195.                         continue;
  196.                     }
  197.                 } else {
  198.                     dm = si.stack;
  199.                 }
  200.                 dprint(1, "dm=" + dm);
  201.                 if(dm < 0) {//check
  202.                     print("??? dm<0");
  203.                     continue;
  204.                 }
  205.                 pushed_slots++;
  206.                 int n_move = Math.Min(dm, si.stack); //dm may gt si.stack
  207.                 dprint(1, "n_move=" + n_move);
  208.                 if(ci.stack + n_move > ci.maxStack) {
  209.                     n_move = ci.maxStack - ci.stack;
  210.                     dprint(1, "limit to maxStack. n_move=" + n_move);
  211.                 }
  212.                 ci.stack += n_move;
  213.                 si.stack -= n_move;
  214.                 pushed_quantity += n_move;
  215.                 if(pi != -1) RuleChest.itemMoved(pi, n_move);
  216.                 if(si.stack == 0) {
  217.                     si.SetDefaults(0, false);
  218.                 } else if(ci.type == 0) {
  219.                     ci = si.Clone();
  220.                     si.SetDefaults(0, false);
  221.                 }
  222.                 if(chest_index > -1 && Main.netMode == 1) {
  223.                     NetMessage.SendData(32, -1, -1, "", chest_index, (float) index2, 0.0f, 0.0f, 0);
  224.                 }
  225.             }
  226.         }
  227.         if(pushed_slots != 0) {
  228.             Main.PlaySound(7, -1, -1, 1);
  229.         }
  230.         return new ChainQuickStackResult(pushed_slots, pushed_quantity, -1, -1);
  231.     }
  232.     public static void quickRefill(int chest_index) {
  233.         /* 
  234.                         print("refill from chest.");
  235.                         refilled_slots++;
  236.                         int n_move = Math.Min(-dm, ci.stack);
  237.                         print("n_move(all)=" + n_move);
  238.                         if(si.stack + n_move > si.maxStack){
  239.                             n_move = si.maxStack - si.stack;
  240.                         }
  241.                         print("n_move(consider chest slot stack)=" + n_move);
  242.                         si.stack += n_move;
  243.                         ci.stack -= n_move;
  244.                         refilled_quantity+=n_move;
  245.                         RuleChest.itemMoved(pi, -n_move);//pi must gte 0
  246.                         if(ci.stack == 0){
  247.                             ci.SetDefaults(0, false);
  248.                         }else if(si.type==0){
  249.                             si = ci.Clone();
  250.                             ci.SetDefaults(0, false);
  251.                         }
  252.         */
  253.     }
  254.  
  255.     public static string getChestInfo(Chest c) {
  256.         if(c == null) return "null";
  257.         return c.ToString() + " : " + c.name;
  258.     }
  259.     public class IndexAndChest {
  260.         public int i;
  261.         public Chest c;
  262.         public IndexAndChest(int idx, Chest cst) {
  263.             this.i = idx;
  264.             this.c = cst;
  265.         }
  266.     }
  267.     public static IndexAndChest[] getChainedChestArray(int chest_index, bool same_icon) {
  268.         Chest c = Main.chest[chest_index];
  269.         int type = Main.tile[c.x, c.y].type; // 21?
  270.         //find left-most chest with same type
  271.         int x = c.x;
  272.         Tile t;
  273.         while(true) {
  274.             if(x - 2 < 0) break;
  275.             t = Main.tile[x - 2, c.y];
  276.             if(t.type != type) break;
  277.             if(same_icon && t.frameX != Main.tile[c.x, c.y].frameX) {
  278.                 break;
  279.             } else {
  280.                 //print("fx,fy=" + t.frameX + ", " + t.frameY);
  281.                 if((t.frameX & 18) == 18 || //right-parts = be gap between two
  282.                        (t.frameY & 18) == 18) {  //lower-parts = different height
  283.                     break;
  284.                 }
  285.             }
  286.             x -= 2;
  287.         }
  288.         int left = x;
  289.         //find right-most
  290.         x = c.x;
  291.         while(true) {
  292.             if(x + 2 > Main.maxTilesX) break;
  293.             t = Main.tile[x + 2, c.y];
  294.             if(t.type != type) break;
  295.             if(same_icon && t.frameX != Main.tile[c.x, c.y].frameX) {
  296.                 break;
  297.             } else if(//(t.frameX&18)==18 || //no need to check
  298.                         (t.frameY & 18) == 18) {  //lower-parts = different height
  299.                 break;
  300.             }
  301.             x += 2;
  302.         }
  303.         int right = x;
  304.         //print("from " + left + " < (" + c.x + ") < " + right);
  305.         //list up chest objects
  306.         int n_chests = (right - left) / 2 + 1;
  307.         IndexAndChest[] cc = new IndexAndChest[n_chests];
  308.         for(int i = 0, n = 0; i < Main.chest.Length; i++) {
  309.             Chest ct = Main.chest[i];
  310.             if(ct != null && ct.y == c.y && (left <= ct.x && ct.x <= right)) {
  311.                 //print(getChestInfo(ct));
  312.                 cc[n++] = new IndexAndChest(i, ct);
  313.                 if(n == n_chests) break;
  314.             }
  315.         }
  316.         // sort by x
  317.         //print("---sorting");
  318.         Array.Sort(cc, (f, s) => f.c.x.CompareTo(s.c.x));
  319.  
  320.         //check is ProtectRuleChest
  321.         foreach(var tp in cc) {
  322.             if(RuleChest.isPrivateRuleChest(tp.c)) {
  323.                 RuleChest.readRuleAndInit(tp.c);// only left-most ProtectRuleChest is read.
  324.                 break;
  325.             }
  326.         }
  327.         return cc;
  328.  
  329.     }
  330.  
  331.     public class ChainQuickStackResult {
  332.         public int n_slots;
  333.         public int quantity;
  334.         public int n_used_chest;
  335.         public int n_chests;
  336.         public ChainQuickStackResult(int ns, int q, int uc, int nc) {
  337.             n_slots = ns;
  338.             quantity = q;
  339.             n_used_chest = uc;
  340.             n_chests = nc;
  341.         }
  342.         public string ToString() {
  343.             if(n_used_chest != -1) {
  344.                 return string.Format("{0,2} slots, {1,4} items, into {2,3}/{3,3} chests", n_slots, quantity, n_used_chest, n_chests);
  345.             }
  346.             return string.Format("{0,2} slots, {1,4} items", n_slots, quantity);
  347.         }
  348.     }
  349.  
  350.     public static ChainQuickStackResult chainQuickStack(int chest_index, bool same_icon) {
  351.         IndexAndChest[] cc = getChainedChestArray(chest_index, same_icon);
  352.  
  353.         // unite inventory for simpliztion
  354.         uniteInventory();
  355.  
  356.         int ns = 0; // slots
  357.         int nq = 0; // quantity
  358.         int n_used_chest = 0;
  359.         foreach(var tp in cc) {
  360.             //print(getChestInfo(tp.Item2));
  361.             ChainQuickStackResult r = quickStack(tp.i);
  362.             if(r != null && r.n_slots != 0) {
  363.                 ns += r.n_slots;
  364.                 nq += r.quantity;
  365.                 n_used_chest++;
  366.             }
  367.         }
  368.         return new ChainQuickStackResult(ns, nq, n_used_chest, cc.Length);
  369.     }
  370.  
  371.     static void printTileInfo(int x, int y) {
  372.         Tile t = Main.tile[x, y];
  373.         if(t == null) {
  374.             print("tile==null");
  375.         } else {
  376.             print("tile={" +
  377.          "type : " + t.type +
  378.                 //   ", wall : " + t.wall +
  379.                 //   ", liquid : " + t.liquid +
  380.                 //   ", sTileHeader : " + t.sTileHeader +
  381.                 //   ", bTileHeader : " + t.bTileHeader +
  382.                 //   ", bTileHeader2 : " + t.bTileHeader2 +
  383.                 //   ", bTileHeader3 : " + t.bTileHeader3 +
  384.          ", frameX : " + t.frameX +
  385.          ", frameY : " + t.frameY +
  386.          "}");
  387.         }
  388.     }
  389.     static void printMapInfo(int x, int y) {
  390.         Map m = Main.map[x, y];
  391.         if(m == null) {
  392.             print("map==null");
  393.         } else {
  394.             print("map={" +
  395.                 "type : " + m.type +
  396.                 ", light : " + m.light +
  397.                 ", misc : " + m.misc +
  398.                 "}");
  399.         }
  400.     }
  401.  
  402.     ///---main
  403.     public static int main() {
  404.         int opened_chest_index = Main.player[Main.myPlayer].chest;
  405.  
  406.         if(opened_chest_index == -1) {
  407.             print("NO CHEST OPENED. uniteInventory()");
  408.             uniteInventory();
  409.             return 0;
  410.         }
  411.  
  412.         ChainQuickStackResult res;
  413.         //bank or safe
  414.         if(opened_chest_index == -2 || opened_chest_index == -3) {
  415.             res = quickStack(opened_chest_index);
  416.         } else { //normal chest
  417.             //Chest c = getChestFromIndex(opened_chest_index);
  418.             //print(getChestInfo(c));
  419.             //printTileInfo(c.x, c.y);
  420.             //printTileInfo(c.x+1, c.y);
  421.             //printTileInfo(c.x, c.y+1);
  422.             //printTileInfo(c.x+1, c.y+1);
  423.             res = chainQuickStack(opened_chest_index, false);
  424.         }
  425.         if(res != null && res.n_slots != 0) {
  426.             print("moved " + res.ToString());
  427.         }
  428.         return 0;
  429.     }
  430. }
  431. //ChainedQuickStack.log_level = 1;
  432. //ChainedQuickStack.uniteInventory();
  433. //ChainedQuickStack.RuleChest.test();
  434. ChainedQuickStack.main();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement