public static IEnumerator LineSurface(Emplacement place, OptionEffect options) { Vector3i shape = options.OptionShape.shape; /// (avancée, hauteur, largeur) Vector3i above = Vectors.Up; Vector3i pos = place.ipos; Vector3i offsetSurface = new Vector3i(0, options.OptionShape.offsetSurface, 0); bool reverse = options.OptionShape.reverse != ""; float pace = options.OptionShape.pace; bool collapse_once = options.OptionShape.reverse == "once"; Block air = Block.GetBlockByName("air", false); Block blk = options.OptionBlock.block; BlockSetter setter = new BlockSetter(options.OptionBlock); /// IntLine traj = new IntLine(place.ipos, Vectors.Float.UnitX); IntLine traj = new IntLine(place.ipos, Emplacement.Truncate(place.direction, true, true)); for (int avance = 0; avance < shape.x; avance++) { Vector3i where = traj.Get(avance); Debug.Log("LineSurface " + avance.ToString()); IntLine orth = new IntLine(Vectors.ToFloat(where), Vectors.Float.UnitZ); foreach (int ligne in LR(shape.z)) { Vector3i at = orth.Get(ligne); //Debug.Log("Line Surface inner " + p.ToString()); at = Geo3D.Surface(at); // I don't need surface before orthogonal ... surface made after setter.Apply(at + above + offsetSurface); } setter.Push(); yield return(new WaitForEndOfFrame()); } }
public IEnumerator _Effect1(EntityPlayer player, Emplacement place, OptionEffect opt) { // Careful, place.direction is the "to" (or I need a range option somewhere, or natural fadeaway) float y = 1.1f; // air above surface (+1) + offset // foreach (Emplacement place in Iter.On(Placer.Get(player.GetPosition()))) { Printer.Log(40, "FireStorm _Effect1:", place, opt.OptionItem.item); // line manage +5; if (place.valid) { // Vector3i at = Geo3D.Surface(Vectors.ToInt(place.position)); Vector3i at = Geo3D.Surface(Vectors.ToInt(place.position), -1, Geo3D.IsGroundOrBuilding); for (int x = 0; x < opt.OptionShape.shape.x; x++) { for (int z = 0; z < opt.OptionShape.shape.z; z++) { Vector3 shift = new Vector3(3 * x, y, 3 * z); // TODO randomize int echos = 1; if (ItemClass.GetItem(opt.OptionItem.item, false).ItemClass.Properties.Contains("Replicates")) { echos = 3; } yield return(Zombiome.Routines.Start( Fire.ThrowItem(Vectors.ToFloat(at) + shift, opt.OptionItem.item, echos), "FireStorm-spawnItemGhost" )); } } } else { Printer.Log(41, "Invalid place:", place, place.valid_msg); } }
public static IEnumerator CactusGrowth(Entity player, Emplacement place, OptionEffect options) { Vector3i where = Geo3D.Surface(place.ipos) + Vectors.Up; string[] cactuses = new String[] { "treeCactus04", "treeCactus05", "treeCactus06", "treeCactus03", "treeCactus02", "treeCactus01" }; foreach (string blk in cactuses) { BlockSetter.SetBlockAt(where, Block.GetBlockByName(blk, false), options); yield return(new WaitForSeconds(1f)); } }
public override void Effect1(EntityPlayer player, Emplacement place, OptionEffect opt) { Printer.Print("SingleChunked Effect1", place.position, place.ipos, opt.OptionItem.item); Vector3i where = Vectors.ToInt(player.GetPosition()); int y0 = Geo3D.Surface(where).y; Vector3i nw4 = ZChunk.TL4(place.ipos); Bounds b4 = ZChunk.Bounds4(nw4, y0); Zombiome.Routines.Start(Regen(player, b4, y0), name + "-SingleChunked"); }
private bool SeeToward(BlockPos deco, BlockPos Target, int idir) { /** -> isSame */ Vector3i dir = Geo3D.SurfaceNeighbourhood.adjacent[idir]; Target.Pos = Geo3D.Surface(deco.Pos + dir) + Vectors.UnitY; Target.Value = World.GetBlock(Target.Pos); Target.Parent(); // should not be needed, but CanSwap does // return deco.SameBlock(Target); if (! deco.SameBlock(Target)) return false; Target.Pos = Geo3D.Surface(deco.Pos + dir) + Vectors.UnitY; // same block, dont point to the same parent, or not motion... Target.Value = BlockValue.Air; return true; }
public static Bounds Bounds(Vector3i chunk, int iniguess, int size = -1) { // I could use 125. Do I need center at surface ? if (size == -1) { size = ZChunk.size; } Vector3i center = Center(chunk); int y0 = Geo3D.Surface(center, iniguess).y; center.y = y0; return(new Bounds(Vectors.ToFloat(center), new Vector3(size, 100, size))); }
public static Bounds Bounds4(Vector3i chunk, int iniguess, int size = -1) { // Union of 4 adjacent <=> Zone twice larger, centered at intersect if (size == -1) { size = ZChunk.size; } Vector3i center = new Vector3i((1 + chunk.x) * size, 0, (1 + chunk.z * size)); int y0 = Geo3D.Surface(center, iniguess).y; center.y = y0; return(new Bounds(Vectors.ToFloat(center), new Vector3(2 * size, 100, 2 * size))); }
public override void Effect1(EntityPlayer player, Emplacement place, OptionEffect opt) { Printer.Log(46, "SingleChunked Effect1", place.position, place.ipos, opt.OptionItem.item); Vector3i where = Vectors.ToInt(player.GetPosition()); int y0 = Geo3D.Surface(where).y; Vector3i nw4 = ZChunk.TL4(place.ipos); Zombiome.Routines.Start(Regen(player, nw4, y0), name + "-SingleChunked0"); Zombiome.Routines.Start(Regen(player, nw4 + new Vector3i(1, 0, 0), y0), name + "-SingleChunked1"); Zombiome.Routines.Start(Regen(player, nw4 + new Vector3i(0, 0, 1), y0), name + "-SingleChunked2"); Zombiome.Routines.Start(Regen(player, nw4 + new Vector3i(1, 0, 1), y0), name + "-SingleChunked3"); }
public static IEnumerator TrapLine(Entity player, Emplacement place, OptionEffect options) { /// TODO: recoder ca avec rift Vector3i offsetSurface = new Vector3i(0, options.OptionShape.offsetSurface, 0); Vector3i pos = place.ipos; // size = E/W=largeur, hauteur, N/S profondeur (portee) Vector3i size = options.OptionShape.shape; Vector3 base_direction = Emplacement.Truncate(place.direction, true, true); float pace = 0.1f; // TODO pace in option Block air = Block.GetBlockByName("air", false); // The air instance could prolly be shared ... // Block blk = options.OptionBlock.block; int portee = 100; BlockSetter setter = new BlockSetter(options.OptionBlock); BlockSetter setterAir = new BlockSetter(options.OptionBlock.Copy()); setterAir.options.block = air; Vector3 posf = Vectors.ToFloat(pos + offsetSurface); // string[] random_blocks = new string[]{"trapSpikesWoodDmg0", "trapSpikesWoodDmg1", "trapSpikesWoodDmg2"}; // Block[] random_blocks = options.OptionBlock.blocks; Vector3i start = Geo3D.Surface(place.ipos); for (int k = 0; k < 10; k++) { Vector3 direction = base_direction + Vectors.Float.Randomize(GameManager.Instance.World.GetGameRandom(), 0.1f); direction.y = 0; direction = direction.normalized; // IntLine traj = new IntLine(start, direction); //east IEnumerable <Vector3i> segment = IntLine.Segment(Vectors.ToFloat(start), direction, 1, 10); // skip 0 intersecting with the previous foreach (Vector3i where in segment) { Vector3i Swhere = Geo3D.Surface(where); // randomisation : "trapSpikesWoodDmg0-2" // string rdm = random_blocks[(int) Math.Floor(GameManager.Instance.World.GetGameRandom().RandomFloat*3)]; // setter.options.block = Block.GetBlockByName(rdm, false); // Block rdm = setter.Apply(Swhere + Vectors.Up); setter.Push(); start = Swhere; yield return(new WaitForEndOfFrame()); } yield return(new WaitForSeconds(0.5f)); } }
public override IEnumerator Regen(EntityPlayer player, Vector3i zchunk, int iniguess) { Bounds bounds = ZChunk.Bounds4(zchunk, iniguess); List <Entity> existing = GameManager.Instance.World.GetEntitiesInBounds( EntityGhost.Concretes[this.concreteIdx], bounds, new List <Entity>() ); yield return(Iterating.Repeater.Frame); // listent may be costly Vector3i min = Vectors.ToInt(bounds.min); Vector3i max = Vectors.ToInt(bounds.max); int current = existing.Count; int gen = ZChunk.Size(this.gen); // gen = 1; // DEBUG int regen = ZChunk.Size(this.regen); int iniy = (int)Math.Floor(player.GetPosition().y); Zombiome.Routines.Start(Routines.IfNotRunning( LockRenew, EffectExisting(player, existing) ), "Ghost-Existing"); int nnew = Math.Min(limit_new, gen - current); Entity[] Tracker = new Entity[] { null }; if (current < regen) { Printer.Log(45, "Ghost regen", regen, current, gen, "=>", gen - current); for (int k = 0; k < nnew; k++) { Vector3i pos = new Vector3i(rand.RandomRange(min.x, max.x), 0, rand.RandomRange(min.z, max.z)); pos = Geo3D.Surface(pos, iniy); if (GameManager.Instance.World.GetTerrainHeight(pos.x, pos.z) > 2) { Printer.Log(40, "Ghost", pos, opt.OptionEntity.entity, opt.OptionEntity.buff); Emplacement place = Emplacement.At(Vectors.ToFloat(pos) + 2f * Vectors.Float.UnitY, Vectors.Float.UnitY); GhostData gdata = (ghost_type == "") ? this.GhostData : GhostData.Ghosts[ghost_type]; yield return(EntityGhost.Create(gdata, place, opt.OptionEntity.entity)); } yield return(Repeater.Yield); } } }
/* * * Options: * - ground (water, traps) * - recursion * - size / depth (puis avant) * - other content : Z, animal, torch, lights ... * */ public static IEnumerator Rift(EntityPlayer player, Emplacement place, OptionEffect options) { /* * Laisse des blocks tomber au dessus ? just changed erase="yes" * (longueur 1, hauteur (profonfeur), replicats) */ EntityPlayerLocal epl = player as EntityPlayerLocal; epl.cameraTransform.SendMessage("ShakeBig"); yield return(new WaitForSeconds(1f)); BlockSetter setter = new BlockSetter(options.OptionBlock); Vector3 direction = Vectors.Copy(place.direction); direction.y = 0; direction = direction.normalized; Vector3i start = Geo3D.Surface(place.ipos); for (int k = 0; k < options.OptionShape.shape.z; k++) { Vector3 kdirection = direction + Vectors.Float.Randomize(GameManager.Instance.World.GetGameRandom(), 0.2f); // IntLine traj = new IntLine(start, direction); //east IEnumerable <Vector3i> segment = IntLine.Segment(Vectors.ToFloat(start), kdirection, 0, options.OptionShape.shape.x); Vector3i prev = new Vector3i(); bool hasprev = false; foreach (Vector3i where in segment) { Vector3i Swhere = Geo3D.Surface(where); setter.Apply(Swhere); if (hasprev) { for (int creuse = 1; creuse < options.OptionShape.shape.y; creuse++) { setter.Apply(prev + creuse * Vectors.Down); } } setter.Push(); start = Swhere; yield return(new WaitForEndOfFrame()); hasprev = true; prev = Swhere; } yield return(new WaitForSeconds(1f)); } }
public IEnumerator<Emplacement> Get(Vector3 position) { int iniy = (int) Math.Floor(position.y); IEnumerator<Vector3> pos = positions.Get(position); while(true) { string valid = ""; /* Extra point near or at player. NB: adds an extra yield */ if (rate_around > 0) { float u = Zombiome.rand.RandomFloat; if (u <= rate_around) { float ray = (u <= rate_at) ? 1f : 5f; yield return Emplacement.At( player.GetPosition() + Vectors.Float.Randomize(Zombiome.rand, ray), directions.Generate(pos.Current) ); } } /* Basic point */ bool continuing = pos.MoveNext(); // false if forward failed if (! continuing) { // Printer.Print("Placer.Get(): stop iteration"); yield break; } int th = GameManager.Instance.World.GetTerrainHeight((int) Math.Floor(pos.Current.x), (int) Math.Floor(pos.Current.z)); if (th == 0) { // Printer.Print("Placer.Get(): Chunk not loaded at", pos.Current); // Printer.Print(" position", position, "->", pos.Current); valid = "th=0"; } // Vector3 where = (this.AtSurface) ? Geo3D.Surface(pos.Current, iniy) : pos.Current; Vector3 where = (this.AtSurface) ? Geo3D.Surface(pos.Current, th) : pos.Current; /* Altitude check */ // if (Math.Abs(th - where.y) > 60) valid = String.Format("y={0} / th={1} < 60", where.y, th); // initial surface if (where.y > th + pOffSurface) valid = String.Format("Surface Offset y={0} / th={1} > pD = {2}", where.y, th, pOffSurface); // initial surface if (where.y < th - nOffSurface) valid = String.Format("Surface Offset y={0} / th={1} < nD = 60", where.y, th, nOffSurface); // initial surface if (where.y <= 1) valid = "y<1"; if (where.y >= 255) valid = "y>254"; // TODO: just stop if too far from player (eg teleport) or Zone center Emplacement place = Emplacement.At(where, directions.Generate(pos.Current)); if (valid.Length > 0) place.Invalid(valid); yield return place; } }
private static void ShowSurface(List <string> _params) { EntityPlayerLocal player = GameManager.Instance.World.GetLocalPlayers()[0]; Vector3i pos = Vectors.ToInt(player.GetPosition()); Vector3i s; if (_params.Count > 0) { pos.x = int.Parse(_params[0]); pos.y = int.Parse(_params[1]); pos.z = int.Parse(_params[2]); } // int dx = 100; // pos.x = pos.x + dx; Printer.Print("GetTerrainHeight", GameManager.Instance.World.GetTerrainHeight(pos.x, pos.z)); s = Geo3D.Surface(pos, -1); Printer.Print("pos", pos, "@", -1, "->", s); s = Geo3D.Surface(pos, -2); Printer.Print("pos", pos, "@", -2, "->", s); pos.y = pos.y + 1; s = Geo3D.Surface(pos, -1); Printer.Print("pos", pos, "@", -1, "->", s); s = Geo3D.Surface(pos, -2); Printer.Print("pos", pos, "@", -2, "->", s); pos.y = pos.y + 1; s = Geo3D.Surface(pos, -1); Printer.Print("pos", pos, "@", -1, "->", s); s = Geo3D.Surface(pos, -2); Printer.Print("pos", pos, "@", -2, "->", s); pos.y = pos.y - 3; s = Geo3D.Surface(pos, -1); Printer.Print("pos", pos, "@", -1, "->", s); s = Geo3D.Surface(pos, -2); Printer.Print("pos", pos, "@", -2, "->", s); pos.y = pos.y - 1; s = Geo3D.Surface(pos, -1); Printer.Print("pos", pos, "@", -1, "->", s); s = Geo3D.Surface(pos, -2); Printer.Print("pos", pos, "@", -2, "->", s); pos.y = 1; s = Geo3D.Surface(pos, -1); Printer.Print("pos", pos, "@", -1, "->", s); s = Geo3D.Surface(pos, -2); Printer.Print("pos", pos, "@", -2, "->", s); pos.y = 0; s = Geo3D.Surface(pos, -1); Printer.Print("pos", pos, "@", -1, "->", s); s = Geo3D.Surface(pos, -2); Printer.Print("pos", pos, "@", -2, "->", s); }
public IEnumerator SpawnBlock(EntityAlive ctrl, Vector3 pos) { Printer.Log(30, "MinEventActionImpactSpawn", ctrl, pos, ctrl.GetPosition()); yield return(new WaitForSeconds((float)this.dt / 1000f)); BlockSetter.Options opt = new BlockSetter.Options(); opt.avoidBlock = false; opt.avoidEntity = false; opt.elastic = 0; opt.SetBlocks(this.block); BlockSetter setter = new BlockSetter(opt); setter.OnCreation = BlockSetter.Rotate; Vector3i ipos = Vectors.ToInt(pos); Vector3i surf = Geo3D.Surface(ipos, ipos.y) + Vectors.Up; // setter.Apply(ipos); // is it pos +1 ? do we need surface ? setter.Apply(surf); setter.Push(); }
private void Request(Bounds area, int index) { Printer.Log(26, "EntityPool Request", index, area); Vector3 pos = Vectors.Float.RandomIn(area.min, area.max); Vector3 surf = Geo3D.Surface(pos, (int)area.center.y); if (surf.y == 0) { Printer.Log(26, "EntityPool.Request th =0", area.center); return; } Entity request = EntityCreation.Spawn( surf + 1.5f * Vectors.Float.UnitY, this.entity ); Entities[index] = null; found[index] = false; ids[index] = request.entityId; reqTimes[index] = DateTime.Now.Millisecond; // TODO: add timeout // found[index] = false; }
public override IEnumerator Regen(EntityPlayer player, Vector3i zchunk, int iniguess) { yield return(ZBActivity.Environment.ZBSounds.Play(ZBiomeInfo.NoiseWater, player.GetPosition(), player, World, 2, 0, 0.5f)); int gen = ZChunk.Size(this.gen); Vector3[] positions = ZChunk.Positions(Zombiome.worldSeed, zchunk, gen); foreach (Vector3 pos in positions) { Printer.Log(40, "Flood regen", zchunk, pos); Vector3i surfaced = Geo3D.Surface(Vectors.ToInt(pos), iniguess); Emplacement place = Emplacement.At(Vectors.ToFloat(surfaced), Vectors.Float.UnitY); /* Generate Emplacement => apply filter from gth */ int th = GameManager.Instance.World.GetTerrainHeight(surfaced.x, surfaced.z); bool go = th > 5; if (go) { go = surfaced.y < th + Placer.pOffSurface; } if (go) { go = surfaced.y > th - Placer.nOffSurface; } if (go) { go = !(IsWater(World.GetBlock(surfaced + Vectors.Up).Block) && IsWater(World.GetBlock(surfaced + 2 * Vectors.Up).Block)); } if (go) { Printer.Log(40, "Flood at", place); // Dont do it if already water, surtout qu'on affaisse la surface !! // Cave allows to bound water by ground yield return(EffectsCollapse.Cave(player, place, opt)); } yield return(Repeater.Yield); } }
public override void Effect1(EntityPlayer player, Emplacement place, OptionEffect opt) { World World = GameManager.Instance.World; Vector3i ipos = place.ipos; Vector3i surf = Geo3D.Surface(ipos, (int)player.GetPosition().y); BlockValue existingB = World.GetBlock(surf + Vectors.Up); string existing = existingB.Block.ToString(); if (existingB.type == 0) // air { BlockValue insert = GenBV(); World.SetBlockRPC(0, surf + Vectors.Up, insert); } else { if (!decorationsSet.Contains(existing)) { return; } } Zombiome.Routines.Start(EffectsGround.Peak(player, place, opt), "FloatingDeco-Peak"); }
public static IEnumerator Rift(EntityPlayer player, Emplacement place, OptionEffect options) { /* * Laisse des blocks tomber au dessus ? just changed erase="yes" */ Vector3i offsetSurface = new Vector3i(0, options.OptionShape.offsetSurface, 0); EntityPlayerLocal epl = player as EntityPlayerLocal; epl.cameraTransform.SendMessage("ShakeBig"); yield return(new WaitForSeconds(1f)); // Vector3i shape = options.OptionShape.shape; /// (longueur, hauteur, largeur) BlockSetter setter = new BlockSetter(options.OptionBlock); Vector3i start = Geo3D.Surface(place.ipos); for (int k = 0; k < 3; k++) { // Vector3 direction = Vectors.Float.UnitX + Vectors.Float.Randomize(GameManager.Instance.World.GetGameRandom(), 0.1f); Vector3 direction = place.direction + Vectors.Float.Randomize(GameManager.Instance.World.GetGameRandom(), 0.1f); direction.y = 0; direction = direction.normalized; // IntLine traj = new IntLine(start, direction); //east IEnumerable <Vector3i> segment = IntLine.Segment(Vectors.ToFloat(start), direction, 1, 5); // skip 0 intersecting with the previous foreach (Vector3i where in segment) { Vector3i Swhere = Geo3D.Surface(where) + offsetSurface; setter.Apply(Swhere); setter.Apply(Swhere + Vectors.Up); setter.Apply(Swhere + 2 * Vectors.Up); setter.Push(); start = Swhere; yield return(new WaitForEndOfFrame()); } yield return(new WaitForSeconds(1f)); } }
public override void Effect1(EntityPlayer player, Emplacement place, OptionEffect opt) { // Vector3i at = Geo3D.Surface(Vectors.ToInt(place.position)); Vector3i at = Geo3D.Surface(Vectors.ToInt(place.position), -1, Geo3D.IsGroundOrBuilding); float y = 1.1f; // air above surface (+1) + offset for (int x = 0; x < opt.OptionShape.shape.x; x++) { for (int z = 0; z < opt.OptionShape.shape.z; z++) { Vector3 shift = new Vector3(2 * x, y, 2 * z); // TODO randomize int echos = 1; if (ItemClass.GetItem(opt.OptionItem.item, false).ItemClass.Properties.Contains("Replicates")) { echos = 3; } // int echos = (opt.OptionItem.item == "") ? 1 : 3; Zombiome.Routines.Start( ThrowItem(Vectors.ToFloat(at) + shift, opt.OptionItem.item, echos), "Fire-ThrowItem" ); } } }
public override void Effect1(EntityPlayer player, Emplacement place, OptionEffect opt) { // Ignore place.direction, regen it // Iter.EverySeconds(ref tMonitor, dtMonitor, this.Monitor(player.GetPosition()), place.position); Vector3i iwhere = place.ipos; iwhere = Geo3D.Surface(iwhere); Vector3 speed = -Vectors.Float.UnitY + Vectors.Float.Randomize(rand, 0.5f); speed = speed.normalized * (50 + 50 * rand.RandomFloat); // weight 100 speed = 0f * speed; // [!] float altitude = 25; Printer.Log(40, "Meteorite Effect1", iwhere, speed, altitude); Vector3 where = Vectors.ToFloat(iwhere) + new Vector3(0f, altitude, 0f); where.y = 254f; // accelere trop ? Zombiome.Routines.Start(EffectsItem.spawnItemGhost( opt.OptionItem.item, where, speed // Vectors.Float.Randomize(GameManager.Instance.World.GetGameRandom(), 1f, speed) ), "Meteorite-spawnItemGhost"); }
public static IEnumerator Cave(EntityPlayer player, Emplacement place, OptionEffect options) { /// TODO: enumérer les colonnes et s'arreter à surface BlockSetter setter = new BlockSetter(options.OptionBlock); Vector3i shape = options.OptionShape.shape; Vector3i start = Geo3D.Surface(place.ipos); int depth = shape.y; Vector3 direction = Vectors.Float.UnitY; // cannot use negative, so positive and get(_k) ! IntLine colonne = new IntLine(Vectors.ToFloat(start), direction); // Debug.Log(String.Format("Cave: pos={0} start={1} dir={2} ground={3}", place.position, start, direction, ground)); for (int d = 0; d < depth; d++) { // Debug.Log(String.Format("cave {0} {1}", d, setter)); if (options.OptionShape.ground != "" && d == depth - 1) { setter.options.block = Block.GetBlockByName(options.OptionShape.ground, false); } Vector3i where = colonne.Get(-d); Vector3i dxy = new Vector3i(0, 0, 0); foreach (int p in SdtdUtils.EffectsGround.LR(shape.x)) { foreach (int q in SdtdUtils.EffectsGround.LR(shape.z)) { dxy.x = p; dxy.z = q; Printer.Log(20, "Cave Apply (d,p) =", d, p, "where, dxy=", where, dxy); setter.Apply(where + dxy); } } Printer.FLog(20, "cave Push {0} {1}", d, where); setter.Push(); } yield return(new WaitForEndOfFrame()); }
public override IEnumerator Apply(EntityPlayer player, EntityAlive target, OptionEffect opt) { Vector3 tpos = target.GetPosition(); Vector3 s = Geo3D.Surface(tpos); if (s.y <= 1) { yield break; } float dy = tpos.y - s.y; if (dy >= 0.5f) { yield break; } if (dy <= -0.5f) { yield break; } Vector3 dir = -0.3f * Vectors.Float.UnitY; EntityMover mover = new EntityMover(1); // .Config(1); yield return(mover.Move(target, dir)); }
/* * public static string Get(IDictionary<string, string> dico, string key, string def) { // UTILS * if (dico.ContainsKey(key)) return dico[key]; * return def; * } */ public static IEnumerator Peak(Entity player, Emplacement place, OptionEffect options) { Vector3i offsetSurface = new Vector3i(0, options.OptionShape.offsetSurface, 0); Vector3i pos = Geo3D.Surface(place.ipos) + Vectors.Up + offsetSurface; Vector3i shape = options.OptionShape.shape; float pace = options.OptionShape.pace; Block air = Block.GetBlockByName("air", false); // The air instance could prolly be shared ... Block blk = options.OptionBlock.block; BlockSetter setter = new BlockSetter(options.OptionBlock); Printer.Log(20, "Peak (position/pos=Surface+Up):", place.ipos, pos); Printer.Log(20, " (blk/pace/shape)", options.OptionBlock.block, options.OptionShape.pace, options.OptionShape.shape); Printer.Log(20, " setter (avB/avE,elastic):", options.OptionBlock.avoidBlock, options.OptionBlock.avoidEntity, options.OptionBlock.elastic); // Start at -1 only if air below for (int h = 0; h < shape.y; h++) { foreach (int e in LR(shape.x)) { foreach (int n in LR(shape.z)) { Vector3i where = new Vector3i(pos.x + e, pos.y + h, pos.z + n); setter.Apply(where); } setter.Push(); yield return(new WaitForSeconds(pace)); } // } if (options.OptionShape.reverse == "") { yield break; } // unset if exists options.OptionBlock.block = air; options.OptionBlock.avoidBlock = false; // protected by testing blk.blockID, and preventing us from actually deleting ! setter = new BlockSetter(options.OptionBlock); // IEnumerable<int> heights = Enumerable.Range(0, shape.y-1); IEnumerable <int> heights = Enumerable.Range(0, shape.y); if (options.OptionShape.reverse.Contains('U')) { } else { heights = Enumerable.Reverse(heights); } foreach (int h in heights) // when destroyed from below, collapse => destroy top to bottom { foreach (int e in LR(shape.x)) { foreach (int n in LR(shape.z)) { Vector3i where = new Vector3i(pos.x + e, pos.y + h, pos.z + n); BlockValue existing = GameManager.Instance.World.GetBlock(where); if (existing.type == blk.blockID) // only erase the type I just inserted { setter.Apply(where); // TODO: reverse once option // yield return new WaitForSeconds(sleep); } } } if (!options.OptionShape.reverse.Contains('O')) /// not once: update progressively { setter.Push(); yield return(new WaitForSeconds(pace)); } } }