public void AddBlock(TankBlock block, IntVector3 pos, OrthoRotation rot) { blocks.Add(block); block.trans.parent = transform; block.trans.localPosition = pos; block.trans.localRotation = rot; Dirty = true; for (int ap = 0; ap < block.attachPoints.Length; ap++) { IntVector3 filledCellForAPIndex = block.GetFilledCellForAPIndex(ap); IntVector3 v3 = block.attachPoints[ap] * 2f - filledCellForAPIndex - filledCellForAPIndex; IntVector3 index = pos + rot * filledCellForAPIndex; byte b = (rot * v3).APHalfBits(); ClusterAPBitField.TryGetValue(index, out byte ptr); ptr |= b; ClusterAPBitField[index] = ptr; } ModuleWeapon weapon = block.GetComponent <ModuleWeapon>(); if (weapon != null) { blockWeapons.Add(weapon); } ModuleDrill drill = block.GetComponent <ModuleDrill>(); if (drill != null) { blockDrills.Add(drill); } return; }
private void Detonate(TechSplitNamer obj) { if (base.block.tank.beam.IsActive) { base.block.tank.beam.EnableBeam(false, false, false); } blockA = block.ConnectedBlocksByAP[0]; blockB = block.ConnectedBlocksByAP[1]; cachedWorldPos = block.trans.position; cachedSplitRot = block.cachedLocalRotation; cachedWorldRot = block.trans.rotation; if (blockA != null) { cachedBlockAOffset = block.cachedLocalPosition - blockA.cachedLocalPosition; } if (blockB != null) { cachedBlockBOffset = block.cachedLocalPosition - blockB.cachedLocalPosition; } if (blockB == null) { blockA.AttachEvent.Subscribe(AfterDetonate); } else { blockB.AttachEvent.Subscribe(AfterDetonate); } Singleton.Manager <ManLooseBlocks> .inst.HostDetachBlock(base.block, false, true); block.damage.Explode(false); // Explode this Detonated = true; }
internal override bool CanStartGetBlocks(BlockManager blockMan) { ClearSegmentList(); // Remove pointers to this block foreach (var m in posCurves) // Clear position animation { m.keys = new Keyframe[1] { new Keyframe(0f, 0f, 0f, 0f, 0f, 0f) } } ; foreach (var m in rotCurves) // Clear rotation animation { m.keys = new Keyframe[1] { new Keyframe(0f, 0f, 0f, 0f, 0f, 0f) } } ; Quaternion TravelQuat = Quaternion.identity; //Vector3 TravelRot = Vector3.zero; OrthoRotation OriginalRot = block.cachedLocalRotation; float Length = starterAnim.AddToAnimCurves(OrthoRotation.identity, this, 0f, ref TravelQuat, starterAnim, 0f);//, ref TravelQuat);//, ref TravelRot); float prevTrueLimitVALUE = TrueLimitVALUE; TrueLimitVALUE = 0f; TankBlock LastBlock = block; AttachPoint LastAP = starterAnim; //For grabbing the block at the next position TankBlock Segment = LastAP.GetBlockAtPos(LastBlock, blockMan); while (Segment != null) { Print(">> Found block " + Segment.cachedLocalPosition); ModuleBMSegment component = Segment.GetComponent <ModuleBMSegment>(); if (component == null) // Not a rail segment { Print(" Not a segment"); ModuleBMRail opposer = Segment.GetComponent <ModuleBMRail>(); if (opposer == null || !LastAP.CanConnect(LastBlock, Segment, opposer.starterAnim)) // Not an opposing rail, or not sharing { break; } // Cut shared rail in half to prevent overlap Print(" Is another head!"); CutSegmentListInHalf(); TrueLimitVALUE = HalfLimitVALUE - 0.5f; // Move back .5 for block-room on the AP break; } if (component.blockMoverHeadType != m_thisHeadType)//component.blockMoverHeadType.Contains(m_thisHeadType)) { Print(" Wrong rail type!"); break; // A different rail system } var _Segment = Segment; Segment = null; // Nullify this, if not re-set it will break the loop for (int i = 0; i < 2; i++) { if (LastAP.CanConnect(LastBlock, _Segment, component.APs[i])) { m_Segments.Add(component); LastBlock = _Segment; LastAP = component.APs[1 - i]; Length = component.APs[i].AddToAnimCurves(Quaternion.Inverse(OriginalRot) * _Segment.cachedLocalRotation, this, Length, ref TravelQuat, LastAP, component.AnimWeight); //, ref TravelQuat);//, ref TravelRot); Segment = LastAP.GetBlockAtPos(_Segment, blockMan); // Set the new segment, continue Print(" Connected!"); break; // Exit the foreach } } if (Segment == null) { Print(">> No more blocks"); } } //if (TrueLimitVALUE == 0f) TrueLimitVALUE = 0.25f; ValidateSegmentList(out bool DisableFreeJoint); CannotBeFreeJoint = true;//DisableFreeJoint; if (MAXVALUELIMIT >= TrueLimitVALUE) { SetMaxLimit(TrueLimitVALUE); if (PVALUE > TrueLimitVALUE) { PVALUE = TrueLimitVALUE; } if (VALUE > TrueLimitVALUE) { VALUE = TrueLimitVALUE; } } else if (prevTrueLimitVALUE == 0f || MAXVALUELIMIT == prevTrueLimitVALUE || !UseLIMIT) { SetMaxLimit(TrueLimitVALUE); } return(true); }
public void AttemptMerge(ModuleFuseHalf other) { // Dot products are basically "Hey how much in this vector is this vector?" // Magnitude relevance of two vectors based on how alike their directions are. // Parallel are A.mag x B.mag, parallel but reverse is -(A.mag x B.mag), right-angle vectors are just 0. // Here dot products are being used to estimate how alike these 1-length directions are to one another. var a = ModelForwardSignificance ? Vector3.Dot(other.transform.forward, ModelForwardPairing * transform.forward) : 1f; // If it matters, are the blocks facing the right way var b = Vector3.Dot(other.transform.up, -transform.up); // Both blocks must be facing upwards at eachother var c = Vector3.Dot(other.block.tank.transform.forward, block.tank.transform.forward); // Both techs must be vertically relevant. var d = Vector3.Dot(other.block.tank.transform.up, block.tank.transform.up); // Both techs must be in the same general direction. I probably could just use quaternion math. //Console.WriteLine($"Testing if sacred ritual may commense:\n Block forward matching = {a}\n Block upward matching = {b}\n Tank forward matching = {c}\n Tank upward matching = {d}"); if (a > 0.85f && b > 0.85f && c > 0.85f && d > 0.85f) { Console.WriteLine($"Commencing the sacred ritual:\n Block forward matching = {a}\n Block upward matching = {b}\n Tank forward matching = {c}\n Tank upward matching = {d}"); //Commence the sacred ritual Tank tankA = block.tank, tankB = other.block.tank; // Tank cache. Because they would be lost without it string tankAName = tankA.name, tankBName = tankB.name; if (Singleton.playerTank == tankB) // If player is tankB it's going to null { Singleton.SetPlayerTankInternal(tankA); // Change it to this tank, because this one is the merge host } Vector3 cachedMergePos = block.cachedLocalPosition; // Where to put the substitute block OrthoRotation cachedMergeRot = block.cachedLocalRotation; // How to put the substitute block List <TankBlock> array = GetSafeBlockStep(other.block); // Iterate the other tech's blocks to get a way to add them all block.tank.blockman.Detach(block, true, false, false); // Remove this block other.block.tank.blockman.Detach(other.block, true, false, false); // Remove that block Quaternion hecku; // Not going to try and figure out all that inverse transformation frick hecku = tankA.transform.rotation; // Yeah that's right get shunned tankB.transform.rotation = tankA.transform.rotation; // They are supposed to be in the same direction anyways so this should be fine tankB.transform.position += transform.position - other.transform.position + (transform.TransformDirection(JoinOffset)); // Move the tech by the offset of the two blocks, and join offset tankB.blockman.Disintegrate(false, false); // Melt that bad boy if (MakeSubstitiute) // Does this have a block to go between or is this one of those glue kinds of fusing { TankBlock mergedBlock = ManSpawn.inst.SpawnBlock(SubstituteType, Vector3.zero, Quaternion.identity); // Create that substitute mergedBlock.SetSkinIndex(block.GetSkinIndex()); // Set that skin so it is pretty mergedBlock.visible.damageable.InitHealth(block.visible.damageable.Health + other.block.visible.damageable.Health); // Set the health to both of the halves tankA.blockman.AddBlockToTech(mergedBlock, cachedMergePos, cachedMergeRot); // Put that block where it belongs } List <TankBlock> retry = new List <TankBlock>(); foreach (TankBlock sb in array) // Iterate from the array back up there from that tech, but now on this tech { // Add the block, using the block's rotation from memory, and just use the block's positions if (!tankA.blockman.AddBlockToTech(sb, block.cachedLocalPosition + sb.cachedLocalPosition - other.block.cachedLocalPosition + block.cachedLocalRotation * JoinOffset, sb.cachedLocalRotation)) /*new IntVector3(tankA.transform.InverseTransformPoint(sb.transform.position))*/ { retry.Add(sb); // If it didn't attach, try again after } } int retryCount = 2; // How many times to retry attaching while (retryCount != 0 && retry.Count != 0) // While there are things left, and can retry { retryCount--; // Spend a token int iter = 0; // Start the iterator while (retry.Count > iter) // Go through the elements { var sb = retry[iter]; if (!tankA.blockman.AddBlockToTech(sb, block.cachedLocalPosition + sb.cachedLocalPosition - other.block.cachedLocalPosition + block.cachedLocalRotation * JoinOffset, sb.cachedLocalRotation)) { iter++; // Skip } else { retry.RemoveAt(iter); // Move elements down, keep placement } } } if (retry.Count != 0) { Console.WriteLine("AttemptMerge(" + tankBName + " to " + tankAName + "): Failed to merge " + retry.Count.ToString() + (retry.Count != 1 ? " blocks!" : " block!")); } tankA.transform.rotation = hecku; // Ok you can come back now block.damage.Explode(false); // Explode this other.block.damage.Explode(false); // Explode that block.visible.RemoveFromGame(); // Rid of this other.block.visible.RemoveFromGame(); // Rid of that } }