Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ///ChainedQuickStack.cs for TerraMod
- // quick stack chained chests.
- // chests which placed horizontally without gap consider as CHAINED.
- // RuleChest
- // name one of chained chest to @<PlayerName> to specify rule of inventory items protection.
- // specified items in inventory will keep Item#maxStack
- // if you want specify number of stacks, name #<PlayerName>
- using System;
- using System.Collections.Generic;
- using Terraria;
- public class ChainedQuickStack {
- static void print(string s) {
- Main.NewText(s);
- }
- public static int log_level = 0;
- static void dprint(int level, string s) {
- if(log_level >= level) print(s);
- }
- public class RuleChest {
- const char PREFIX_MAX_STACK = '@';
- const char PREFIX_N_STACK = '#';
- static bool mode_n_stack = false;
- private static List<Item> items = new List<Item>();
- private static List<int> n_stacks = new List<int>();
- private static List<int> n_possess = new List<int>();
- public static bool isRuleChest(Chest c) {
- return (c.name != string.Empty && (c.name[0] == PREFIX_MAX_STACK || c.name[0] == PREFIX_N_STACK));
- }
- public static bool isPrivateRuleChest(Chest c) {
- string pn = Main.player[Main.myPlayer].name;
- return isRuleChest(c) && string.Compare(c.name, 1, pn, 0, pn.Length, true)==0;
- }
- public static void readRuleAndInit(Chest c) {
- if(c == null) {
- print("??? c==null");
- return;
- }
- if(items.Count != 0) {
- print("only one RuleChest is allowed.");
- return;
- }
- mode_n_stack = (c.name[0] == PREFIX_N_STACK);
- foreach(Item i in c.item) {
- if(i.type <= 0) continue;//empty slot?
- //find same Item
- int add_to = -1;
- for(int x = 0; x < items.Count; x++) {
- if(items[x].IsTheSameAs(i)) {
- add_to = x;
- break;
- }
- }
- if(add_to == -1) {// first type
- items.Add(i);
- n_stacks.Add(mode_n_stack ? i.stack : i.maxStack);
- } else { // type already added
- if(mode_n_stack) {
- n_stacks[add_to] += i.stack;
- }
- }
- }
- //count protected item in inventory
- foreach(Item i in items) {
- int np = 0;
- foreach(Item j in Main.player[Main.myPlayer].inventory) {
- if(j.type <= 0) continue;
- if(j.IsTheSameAs(i)) {
- np += j.stack;
- }
- }
- n_possess.Add(np);
- }
- }
- public static bool needProtect() {
- return items.Count != 0;
- }
- public static bool needRefill() {
- for(int i = 0; i < items.Count; i++) {
- if(n_possess[i] < items[i].maxStack) return true;
- }
- return false;
- }
- public static int findProtectedItem(Item si) {
- for(int i = 0; i < items.Count; i++) {
- if(items[i].IsTheSameAs(si)) return i;
- }
- return -1;
- }
- public static int getDiffToMove(int i) {
- if(i < 0 || i >= n_possess.Count || i >= n_stacks.Count) {
- print("??? getDiffToMove() invalid i=" + i);
- return 0;
- }
- return n_possess[i] - n_stacks[i];
- }
- public static void itemMoved(int i, int dm) {
- if(i < 0 || i >= n_possess.Count) {
- print("??? itemMoved() invalid i=" + i);
- return;
- }
- n_possess[i] -= dm;
- }
- public static void test() {
- log_level = 1;
- chainQuickStack(Main.player[Main.myPlayer].chest, false);
- //Chest c = Main.chest[Main.player[Main.myPlayer].chest];
- //print(Main.player[Main.myPlayer].name);
- //print("isProtectChest()=" +isProtectChest(c));
- //readRuleAndInit(c);
- //print("mns=" + mode_n_stack);
- //print("items.Count=" + items.Count);
- //print("n_possess.Count=" + n_possess.Count);
- //for(int i=0;i<items.Count;i++){
- // print(string.Format("{0,2}:{1,3}:{2,3}:{3}", i, n_stacks[i], n_possess[i], items[i].name));
- //}
- }
- }
- public static Chest getChestFromIndex(int i) {
- if(i <= -4 || i >= Main.chest.Length) return null;
- if(i == -1) return null;
- if(i == -2) return Main.player[Main.myPlayer].bank;
- if(i == -3) return Main.player[Main.myPlayer].bank2;
- return Main.chest[i];
- }
- public static void uniteInventory() {
- Item[] inv = Main.player[Main.myPlayer].inventory;
- Item[] items = new Item[50 + 4];//10*5+ 4(ammo), dont process coins
- Array.Copy(inv, 54, items, 0, 4); // process ammo first.
- Array.Copy(inv, 0, items, 4, 50);// hotbar and rest
- dprint(1, "using shifted items[] : Ammo-Hotbar-rest");
- for(int i = 0; i < items.Length - 1; i++) {// no need to process last one
- if(items[i].type <= 0) continue;//empty slot
- if(items[i].stack == items[i].maxStack) continue; // max stacked
- dprint(1, string.Format("Unite slot {0}, {1}", i, items[i].ToString()));
- for(int j = items.Length - 1; j >= i + 1; j--) { // find from tail
- if(items[j].type <= 0) continue;//empty slot
- if(!items[i].IsTheSameAs(items[j])) continue;//cannot use IsNotTheSameAs() which checks item.stack...
- int n_move = items[j].stack;
- if(items[i].stack + n_move > items[i].maxStack) {
- n_move = items[i].maxStack - items[i].stack;
- }
- dprint(1, string.Format(" moved from slot {0}, n_move={1}", j, n_move));
- items[i].stack += n_move;
- items[j].stack -= n_move;
- if(items[j].stack == 0) {
- items[j].SetDefaults(0, false);
- }
- if(items[i].stack == items[i].maxStack) break;// stack to max
- }
- }
- }
- public static ChainQuickStackResult quickStack(int chest_index) {
- if(chest_index == -1 || chest_index <= -4) {
- print("Invalid chest_index=" + chest_index);
- return null;
- }
- if(RuleChest.isRuleChest(getChestFromIndex(chest_index))) {
- dprint(1, "ignore ProtectRuleChest");
- return null;
- }
- Item[] item = getChestFromIndex(chest_index).item; //chest items
- Item[] inv = Main.player[Main.myPlayer].inventory;//inventory items
- Main.MoveCoins(inv, item);//cannot detect move or not
- bool need_protect = RuleChest.needProtect();
- int pushed_slots = 0;
- int pushed_quantity = 0;
- for(int index2 = 0; index2 < Chest.maxItems; ++index2)// chest loop
- {
- Item ci = item[index2]; //chest item
- if(ci.type <= 0 || ci.stack >= ci.maxStack) continue;//empty or max stacked
- for(int index3 = 57; index3 >= 0; --index3) { // scan inventory reverse to protect left-top items
- Item si = inv[index3]; //source item
- if(!ci.IsTheSameAs(si)) continue;
- int pi = need_protect ? RuleChest.findProtectedItem(si) : -1;//process ProtectedChest if(pi!=-1)
- int dm = 0; //d-move
- dprint(1, "pi = " + pi);
- if(pi != -1) {
- dm = RuleChest.getDiffToMove(pi);
- if(dm <= 0) {
- dprint(1, "dm<=0, through " + si.ToString());
- continue;
- }
- } else {
- dm = si.stack;
- }
- dprint(1, "dm=" + dm);
- if(dm < 0) {//check
- print("??? dm<0");
- continue;
- }
- pushed_slots++;
- int n_move = Math.Min(dm, si.stack); //dm may gt si.stack
- dprint(1, "n_move=" + n_move);
- if(ci.stack + n_move > ci.maxStack) {
- n_move = ci.maxStack - ci.stack;
- dprint(1, "limit to maxStack. n_move=" + n_move);
- }
- ci.stack += n_move;
- si.stack -= n_move;
- pushed_quantity += n_move;
- if(pi != -1) RuleChest.itemMoved(pi, n_move);
- if(si.stack == 0) {
- si.SetDefaults(0, false);
- } else if(ci.type == 0) {
- ci = si.Clone();
- si.SetDefaults(0, false);
- }
- if(chest_index > -1 && Main.netMode == 1) {
- NetMessage.SendData(32, -1, -1, "", chest_index, (float) index2, 0.0f, 0.0f, 0);
- }
- }
- }
- if(pushed_slots != 0) {
- Main.PlaySound(7, -1, -1, 1);
- }
- return new ChainQuickStackResult(pushed_slots, pushed_quantity, -1, -1);
- }
- public static void quickRefill(int chest_index) {
- /*
- print("refill from chest.");
- refilled_slots++;
- int n_move = Math.Min(-dm, ci.stack);
- print("n_move(all)=" + n_move);
- if(si.stack + n_move > si.maxStack){
- n_move = si.maxStack - si.stack;
- }
- print("n_move(consider chest slot stack)=" + n_move);
- si.stack += n_move;
- ci.stack -= n_move;
- refilled_quantity+=n_move;
- RuleChest.itemMoved(pi, -n_move);//pi must gte 0
- if(ci.stack == 0){
- ci.SetDefaults(0, false);
- }else if(si.type==0){
- si = ci.Clone();
- ci.SetDefaults(0, false);
- }
- */
- }
- public static string getChestInfo(Chest c) {
- if(c == null) return "null";
- return c.ToString() + " : " + c.name;
- }
- public class IndexAndChest {
- public int i;
- public Chest c;
- public IndexAndChest(int idx, Chest cst) {
- this.i = idx;
- this.c = cst;
- }
- }
- public static IndexAndChest[] getChainedChestArray(int chest_index, bool same_icon) {
- Chest c = Main.chest[chest_index];
- int type = Main.tile[c.x, c.y].type; // 21?
- //find left-most chest with same type
- int x = c.x;
- Tile t;
- while(true) {
- if(x - 2 < 0) break;
- t = Main.tile[x - 2, c.y];
- if(t.type != type) break;
- if(same_icon && t.frameX != Main.tile[c.x, c.y].frameX) {
- break;
- } else {
- //print("fx,fy=" + t.frameX + ", " + t.frameY);
- if((t.frameX & 18) == 18 || //right-parts = be gap between two
- (t.frameY & 18) == 18) { //lower-parts = different height
- break;
- }
- }
- x -= 2;
- }
- int left = x;
- //find right-most
- x = c.x;
- while(true) {
- if(x + 2 > Main.maxTilesX) break;
- t = Main.tile[x + 2, c.y];
- if(t.type != type) break;
- if(same_icon && t.frameX != Main.tile[c.x, c.y].frameX) {
- break;
- } else if(//(t.frameX&18)==18 || //no need to check
- (t.frameY & 18) == 18) { //lower-parts = different height
- break;
- }
- x += 2;
- }
- int right = x;
- //print("from " + left + " < (" + c.x + ") < " + right);
- //list up chest objects
- int n_chests = (right - left) / 2 + 1;
- IndexAndChest[] cc = new IndexAndChest[n_chests];
- for(int i = 0, n = 0; i < Main.chest.Length; i++) {
- Chest ct = Main.chest[i];
- if(ct != null && ct.y == c.y && (left <= ct.x && ct.x <= right)) {
- //print(getChestInfo(ct));
- cc[n++] = new IndexAndChest(i, ct);
- if(n == n_chests) break;
- }
- }
- // sort by x
- //print("---sorting");
- Array.Sort(cc, (f, s) => f.c.x.CompareTo(s.c.x));
- //check is ProtectRuleChest
- foreach(var tp in cc) {
- if(RuleChest.isPrivateRuleChest(tp.c)) {
- RuleChest.readRuleAndInit(tp.c);// only left-most ProtectRuleChest is read.
- break;
- }
- }
- return cc;
- }
- public class ChainQuickStackResult {
- public int n_slots;
- public int quantity;
- public int n_used_chest;
- public int n_chests;
- public ChainQuickStackResult(int ns, int q, int uc, int nc) {
- n_slots = ns;
- quantity = q;
- n_used_chest = uc;
- n_chests = nc;
- }
- public string ToString() {
- if(n_used_chest != -1) {
- return string.Format("{0,2} slots, {1,4} items, into {2,3}/{3,3} chests", n_slots, quantity, n_used_chest, n_chests);
- }
- return string.Format("{0,2} slots, {1,4} items", n_slots, quantity);
- }
- }
- public static ChainQuickStackResult chainQuickStack(int chest_index, bool same_icon) {
- IndexAndChest[] cc = getChainedChestArray(chest_index, same_icon);
- // unite inventory for simpliztion
- uniteInventory();
- int ns = 0; // slots
- int nq = 0; // quantity
- int n_used_chest = 0;
- foreach(var tp in cc) {
- //print(getChestInfo(tp.Item2));
- ChainQuickStackResult r = quickStack(tp.i);
- if(r != null && r.n_slots != 0) {
- ns += r.n_slots;
- nq += r.quantity;
- n_used_chest++;
- }
- }
- return new ChainQuickStackResult(ns, nq, n_used_chest, cc.Length);
- }
- static void printTileInfo(int x, int y) {
- Tile t = Main.tile[x, y];
- if(t == null) {
- print("tile==null");
- } else {
- print("tile={" +
- "type : " + t.type +
- // ", wall : " + t.wall +
- // ", liquid : " + t.liquid +
- // ", sTileHeader : " + t.sTileHeader +
- // ", bTileHeader : " + t.bTileHeader +
- // ", bTileHeader2 : " + t.bTileHeader2 +
- // ", bTileHeader3 : " + t.bTileHeader3 +
- ", frameX : " + t.frameX +
- ", frameY : " + t.frameY +
- "}");
- }
- }
- static void printMapInfo(int x, int y) {
- Map m = Main.map[x, y];
- if(m == null) {
- print("map==null");
- } else {
- print("map={" +
- "type : " + m.type +
- ", light : " + m.light +
- ", misc : " + m.misc +
- "}");
- }
- }
- ///---main
- public static int main() {
- int opened_chest_index = Main.player[Main.myPlayer].chest;
- if(opened_chest_index == -1) {
- print("NO CHEST OPENED. uniteInventory()");
- uniteInventory();
- return 0;
- }
- ChainQuickStackResult res;
- //bank or safe
- if(opened_chest_index == -2 || opened_chest_index == -3) {
- res = quickStack(opened_chest_index);
- } else { //normal chest
- //Chest c = getChestFromIndex(opened_chest_index);
- //print(getChestInfo(c));
- //printTileInfo(c.x, c.y);
- //printTileInfo(c.x+1, c.y);
- //printTileInfo(c.x, c.y+1);
- //printTileInfo(c.x+1, c.y+1);
- res = chainQuickStack(opened_chest_index, false);
- }
- if(res != null && res.n_slots != 0) {
- print("moved " + res.ToString());
- }
- return 0;
- }
- }
- //ChainedQuickStack.log_level = 1;
- //ChainedQuickStack.uniteInventory();
- //ChainedQuickStack.RuleChest.test();
- ChainedQuickStack.main();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement