public void AddLiquid(int amount, Vector2 pos) { if (amount <= 0) return; if (pos.X < 0) pos.X = 0; if (pos.Y < 0) pos.Y = 0; if (pos.X >= W) pos.X = W - 1; if (pos.Y >= H) pos.Y = H - 1; fixed (TileMapElement* tptr = tileMap) for (int i = 0; i < W * H; i++) (*(tptr + i)).updated = false; List<long> open = new List<long>(); int curind = 0; fixed (TileMapElement* ptrmap = tileMap) { open.Add((long)(ptrmap + (int)pos.X * H + (int)pos.Y)); while (open.Count > curind && amount > 0) { a = (TileMapElement*)((long)open[curind]); curind++; //(*a).updated = true; if ((*a).Free && (*a).level < MaxLevel) { if ((*a).level + amount >= MaxLevel) { wasChanged = true; amount -= (MaxLevel - (*a).level); (*a).level = MaxLevel; } else { wasChanged = true; (*a).level += amount; amount = 0; } } if ((*a).x > 0 && !(*(l = a - H)).updated)//left { open.Add((long)l); (*l).updated = true; } if ((*a).x < W - 1 && !(*(l = a + H)).updated)//right { open.Add((long)l); (*l).updated = true; } if ((*a).y > 0 && !(*(l = a - 1)).updated)//up { open.Add((long)l); (*l).updated = true; } if ((*a).y < H - 1 && !(*(l = a + 1)).updated)//down { open.Add((long)l); (*l).updated = true; } } } }
//TODO optimize private unsafe void _updatePass() { if (!wasChanged) { return; } wasChanged = false; int x, y; updateSideSwapper++; if (updateSideSwapper >= 3) { updateSideSwapper = 0; } bool ussb = updateSideSwapper > 0; int inc = ussb ? 1 : -1; int start = ussb ? 0 : W - 1; fixed(TileMapElement *ptrmap = tileMap) { for (y = H - 1; y >= 0; y--) { //swapps between starting from left and starting from right for (x = start; (ussb && x < W) || (!ussb && x >= 0); x += inc) { a = ptrmap + y + x * H; if ((*a).level != 0) { l = x > 0 ? ptrmap + y + (x - 1) * H : null; r = x < W - 1 ? ptrmap + y + (x + 1) * H : null; d = y < H - 1 ? ptrmap + (y + 1) + x * H : null; l = (l != null && (*l).Free) ? l : null; r = (r != null && (*r).Free) ? r : null; d = (d != null && (*d).Free) ? d : null; if (d != null && (*d).level != MaxLevel)//drop down { wasChanged = true; if ((*d).level + (*a).level <= MaxLevel) { (*d).level += (*a).level; (*a).level = 0; continue; } else { (*a).level -= MaxLevel - (*d).level; (*d).level = MaxLevel; } } //split left and right if (r != null) { if (l == null) { if ((*a).level < 2 && (*r).level < 2) { continue; } int lev = (*r).level + (*a).level; if ((*a).level != lev / 2) { wasChanged = true; } (*r).level = lev / 2; (*a).level = (*r).level; if (lev % 2 == 1) { (*r).level++; } continue; } else { if ((*a).level < 2 && (*r).level < 2 && (*l).level < 2) { continue; } int lev = (*l).level + (*a).level + (*r).level; if ((*a).level != lev / 3) { wasChanged = true; } (*l).level = lev / 3; (*r).level = (*l).level; (*a).level = (*l).level; if (lev % 3 >= 1) { (*r).level++; } if (lev % 3 == 2) { (*l).level++; } continue; } } if (l != null) { if ((*a).level < 2 && (*l).level < 2) { continue; } int lev = (*l).level + (*a).level; if ((*a).level != lev / 2) { wasChanged = true; } (*l).level = lev / 2; (*a).level = (*l).level; if (lev % 2 == 1) { (*l).level++; } continue; } } } } } }
//TODO optimize private unsafe void _updatePass() { if (!wasChanged) return; wasChanged = false; int x, y; updateSideSwapper++; if (updateSideSwapper >= 3) updateSideSwapper = 0; bool ussb = updateSideSwapper > 0; int inc = ussb ? 1 : -1; int start = ussb ? 0 : W - 1; fixed (TileMapElement* ptrmap = tileMap) { for (y = H - 1; y >= 0; y--) { //swapps between starting from left and starting from right for (x = start; (ussb && x < W) || (!ussb && x >= 0); x += inc) { a = ptrmap + y + x * H; if ((*a).level != 0) { l = x > 0 ? ptrmap + y + (x - 1) * H : null; r = x < W - 1 ? ptrmap + y + (x + 1) * H : null; d = y < H - 1 ? ptrmap + (y + 1) + x * H : null; l = (l != null && (*l).Free) ? l : null; r = (r != null && (*r).Free) ? r : null; d = (d != null && (*d).Free) ? d : null; if (d != null && (*d).level != MaxLevel)//drop down { wasChanged = true; if ((*d).level + (*a).level <= MaxLevel) { (*d).level += (*a).level; (*a).level = 0; continue; } else { (*a).level -= MaxLevel - (*d).level; (*d).level = MaxLevel; } } //split left and right if (r != null) { if (l == null) { if ((*a).level < 2 && (*r).level < 2) continue; int lev = (*r).level + (*a).level; if ((*a).level != lev / 2) wasChanged = true; (*r).level = lev / 2; (*a).level = (*r).level; if (lev % 2 == 1) (*r).level++; continue; } else { if ((*a).level < 2 && (*r).level < 2 && (*l).level < 2) continue; int lev = (*l).level + (*a).level + (*r).level; if ((*a).level != lev / 3) wasChanged = true; (*l).level = lev / 3; (*r).level = (*l).level; (*a).level = (*l).level; if (lev % 3 >= 1) (*r).level++; if (lev % 3 == 2) (*l).level++; continue; } } if (l != null) { if ((*a).level < 2 && (*l).level < 2) continue; int lev = (*l).level + (*a).level; if ((*a).level != lev / 2) wasChanged = true; (*l).level = lev / 2; (*a).level = (*l).level; if (lev % 2 == 1) (*l).level++; continue; } } } } } }
public void SetAmount(int amount) { if (amount < 0) return; if (amount == 0) { fixed (TileMapElement* ptrmap = tileMap) { for (int i = 0; i < W*H; i++) { (*(ptrmap + i)).level = 0; } return; } } wasChanged = true; fixed (TileMapElement* ptrmap = tileMap) { for (int y = H - 1; y >= 0 && amount > 0; y--) for (int x = 0; x < W && amount > 0; x++) { if ((*(a = ptrmap + y + x * H)).Free) { if (amount > MaxLevel) { (*a).level = MaxLevel; amount -= MaxLevel; } else { (*a).level = amount; amount = 0; } } } } }
public void RemoveFromTop(int amount) { if (amount <= 0) return; wasChanged = true; fixed (TileMapElement* ptrmap = tileMap) { for (int y = 0; y < H; y++) for (int x = 0; x < W; x++) { if ((*(a = ptrmap + y + x * H)).Free && (*a).level > 0) { if ((*a).level > amount) { (*a).level -= amount; return; } else { amount -= (*a).level; (*a).level = 0; } } } } }
public void RemoveFromBottom(int amount) { if (amount <= 0) return; wasChanged = true; int t = amount > W * 4 ? 4 : amount / 4 / W + 1; fixed (TileMapElement* ptrmap = tileMap) { while (true)//for if t < 4 and not enough after all passes { for (int y = H - 1; y >= 0; y--) for (int x = 0; x < W; x++) { if ((*(a = ptrmap + y + x * H)).Free && (*a).level > 0) { if (t >= amount && (*a).level >= amount) { (*a).level -= amount; return; } else { amount -= t; (*a).level -= t; } } } } } }
public int GetHeightAt(int x) { if (x < 0) x = 0; if (x >= W) x = W - 1; fixed (TileMapElement* ptrmap = tileMap) { int h = 0; for (int y = H - 1; y >= 0; y--) { if ((*(a = ptrmap + y + x * H)).Free && (*a).level == 4) h++; else return h; } return h; } }