public ItemTeleporter(XElement element) : base(element) { var typeElement = element.Element("type"); var failElement = element.Element("fail"); if (typeElement != null) { Type = (string)typeElement; } if (failElement != null) { OnFail = (PathingResult)Enum.Parse(typeof(PathingResult), (string)failElement); } else { OnFail = PathingResult.Interrupted; } }
public PathingResult FindPath(object fromObject, object toObject, bool drawDebug = false) { PathingResult result = new PathingResult(); result.isValid = false; float debugDelay = 0f; const float debugTime = 20000000f; if (drawDebug) { DebugDrawers.Clear(); } if ( fromObject == null || toObject == null || fromObject == toObject ) { return(result); } // Result node variables. foreach (DictionaryEntry entry in this.nodes) { Node node = (Node)entry.Value; node.isQueued = false; node.minDistance = Mathf.Infinity; } Node fromNode = (Node)this.nodes[fromObject]; Node toNode = (Node)this.nodes[toObject]; if (fromNode == null || toNode == null || !fromNode.isEnabled || !toNode.isEnabled) { return(result); } fromNode.minDistance = 0f; Queue <Node> nodesToTest = new Queue <Node>(); nodesToTest.Enqueue(fromNode); Node currentNode; while (true) { // Tested all nodes we can reach. if (nodesToTest.Count == 0) { break; } currentNode = nodesToTest.Dequeue(); foreach (Connection connection in currentNode.connections) { Node node = connection.node; if (node.isEnabled == false) { continue; } node.minDistance = Mathf.Min( node.minDistance, currentNode.minDistance + connection.distance ); if (node.isQueued == false) { nodesToTest.Enqueue(node); node.isQueued = true; } if (drawDebug) { DebugDrawers.SpawnLine( currentNode.pos, node.pos, Color.blue, debugTime - debugDelay, debugDelay ); debugDelay += 0.02f; } } if (currentNode == toNode) { break; } } // No path. if (toNode.isQueued == false) { return(result); } result.distance = toNode.minDistance; result.isValid = true; result.nodes = new List <object>(); result.nodes.Add(toNode.o); // Trace toNode to fromNode, following the shortest path. currentNode = toNode; Node lastNode = null; while (true) { float minMinDistance = Mathf.Infinity; Node bestNode = null; foreach (Connection connection in currentNode.connections) { if (connection.node.isEnabled == false) { continue; } if (connection.node.minDistance < minMinDistance) { minMinDistance = connection.node.minDistance; bestNode = connection.node; } } if (drawDebug) { foreach (Connection connection in currentNode.connections) { if (connection.node.isEnabled == false) { continue; } if (connection.node != bestNode && connection.node != lastNode) { DebugDrawers.SpawnLine( currentNode.pos, connection.node.pos, Color.yellow, debugTime - debugDelay, debugDelay ); } } DebugDrawers.SpawnLine( currentNode.pos, bestNode.pos, Color.green, debugTime - debugDelay, debugDelay ); debugDelay += 0.33f; } lastNode = currentNode; result.nodes.Add(bestNode.o); if (bestNode == fromNode) { break; } else { currentNode = bestNode; } } result.nodes.Reverse(); return(result); }
void HexTileHovered() { bool isHoveredTileGOActive = this.hoveredTile != null; if (this.state == BattleState.AiControl) { isHoveredTileGOActive = false; } else if (this.state == BattleState.MoveAction) { foreach (BattleTile tile in this.moveActionData.ghostMechTiles) { tile.mapTile.RemoveLayer(MapTile.Layer.GhostSprite); } this.moveActionData.ghostMechTiles.Clear(); if (this.moveActionData.losLinesGO) { Destroy(this.moveActionData.losLinesGO); } this.moveActionData.losLinesGO = new GameObject("LOS lines"); this.moveActionData.losLinesGO.transform.parent = this.worldGO.transform; this.ResetActionPointsPreview(); this.moveActionData.pathingResult = this.pathNetwork.FindPath( this.selectedTile, this.hoveredTile ); if (this.CanClickTile() == false) { goto end; } PathingResult result = this.moveActionData.pathingResult.Value; if (result.isValid == false) { goto end; } // Create ghost mechs this.moveActionData.ghostMechTiles.Capacity = result.nodes.Count - 1; GameObject prevGO = this.selectedTile.gameObject; GameObject currentGO; for (int n = 1; n < result.nodes.Count; ++n) { BattleTile tile = (BattleTile)result.nodes[n]; this.moveActionData.ghostMechTiles.Add(tile); currentGO = tile.gameObject; bool right = currentGO.transform.position.x > prevGO.transform.position.x; tile.mapTile.SetLayer( MapTile.Layer.GhostSprite, sprite: this.selectedTile.mech.data.sprite, flipX: right, color: new Color(1.0f, 1.0f, 1.0f, 0.5f) ); prevGO = currentGO; } // Create LOS lines from each tile to the target BattleMech target = this.selectedTile.mech.target; if (target && this.selectedTile.mech.fireAuto) { for (int n = 1; n < result.nodes.Count; ++n) { BattleTile tile = (BattleTile)result.nodes[n]; GameObject go = (GameObject)Instantiate(Resources.Load("Prefabs/LOS line")); go.transform.parent = this.moveActionData.losLinesGO.transform; float offsetOutward = 0.33f; Vector3 dir = (target.tile.transform.position - tile.transform.position).normalized; Vector3 pos1 = tile.transform.position + dir * offsetOutward; Vector3 pos2 = target.tile.transform.position - dir * offsetOutward; float height = 0.25f; pos1.y += height; pos2.y += height; LineRenderer lr = go.GetComponent <LineRenderer>(); lr.SetPositions(new Vector3[] { pos1, pos2 }); bool canSee = this.TestLOS(tile, target.tile); Color lineColor = canSee ? Color.green : Color.red; lr.startColor = lineColor; lr.endColor = lineColor; } } // Update action point UI element. float apRequired = this.selectedTile.mech.GetAPCostForMove(result.nodes).ap; this.UpdateActionPointsPreview(this.selectedTile.mech.actionPoints - apRequired); } end: if (isHoveredTileGOActive) { this.mapDisplay.SetHoveredTile(this.hoveredTile.mapTile); this.mapDisplay.SetHoveredTileValid(this.CanClickTile()); } else { this.mapDisplay.DisableHoveredTile(); } }
// Note: this will be used for replays and maybe save files, so only use data from the move data // and the current state of the map. // Hmmmm, this is starting to seem very independent from the rest of this file. public void ExecuteMove(object o) { if (o.GetType() == typeof(BattleMove.Move)) { var move = (BattleMove.Move)o; Assert.IsTrue( this.GetTile(move.mechIndex).mech != null && this.GetTile(move.newIndex).mech == null && (move.isFiring == false || this.GetTile(move.targetMechIndex).mech != null) ); BattleMech mech = this.GetTile(move.mechIndex).mech; BattleMech targetMech = move.isFiring ? this.GetTile(move.targetMechIndex).mech : null; BattleTile fromTile = mech.tile; BattleTile toTile = this.GetTile(move.newIndex); this.pathNetwork.SetNodeEnabled(fromTile, true); PathingResult result = this.pathNetwork.FindPath(fromTile, toTile); Assert.IsTrue(result.isValid); bool isFiring = move.isFiring; BattleTile prevTile = (BattleTile)result.nodes[0]; for (int n = 1; n < result.nodes.Count; ++n) { BattleTile currentTile = (BattleTile)result.nodes[n]; prevTile.mech = null; currentTile.mech = mech; mech.tile = currentTile; if (isFiring) { bool canSeeTarget = this.TestLOS(currentTile, targetMech.tile); if (canSeeTarget) { this.MechAttack(mech, targetMech); if (targetMech.isDestroyed) { isFiring = false; } } } prevTile = currentTile; } mech.PlaceAtMapTile(toTile.mapTile); BattleTile lastTile1 = (BattleTile)result.nodes[result.nodes.Count - 2]; BattleTile lastTile2 = (BattleTile)result.nodes[result.nodes.Count - 1]; bool right = lastTile2.transform.position.x > lastTile1.transform.position.x; MechDirection newDir = right ? MechDirection.Right : MechDirection.Left; mech.SetDirection(newDir); var apCostResult = mech.GetAPCostForMove(result.nodes); Assert.IsTrue(mech.actionPoints > 0); mech.actionPoints -= apCostResult.ap; this.pathNetwork.SetNodeEnabled(toTile, false); this.UpdateFogOfWar(); } else if (o.GetType() == typeof(BattleMove.StandingFire)) { var move = (BattleMove.StandingFire)o; Assert.IsTrue( this.GetTile(move.mechIndex).mech != null && this.GetTile(move.targetMechIndex).mech != null ); BattleMech mech = this.GetTile(move.mechIndex).mech; BattleMech targetMech = this.GetTile(move.targetMechIndex).mech; this.MechAttack(mech, targetMech); var apCostResult = mech.GetAPCostForStandingFire(); mech.actionPoints -= apCostResult.ap; } else if (o.GetType() == typeof(BattleMove.SetTarget)) { var move = (BattleMove.SetTarget)o; Assert.IsTrue( this.GetTile(move.mechIndex).mech != null && (move.hasTarget == false || this.GetTile(move.targetMechIndex).mech != null) ); BattleMech mech = this.GetTile(move.mechIndex).mech; if (move.hasTarget) { mech.target = this.GetTile(move.targetMechIndex).mech; } else { mech.target = null; } } else { throw new UnityException(); } // Add to battle history. this.history.moves.Add(o); // Determine if this team's turn is over so we can advance the turn. bool hasAP = false; foreach (BattleMech mech in this.currentTeam.mechs) { if (mech.actionPoints > 0) { hasAP = true; break; } } if (hasAP == false) { this.AdvanceTurn(); } }
void Update() { if (hardInput.GetKeyDown("Test LOS")) { // Draw a LOS test line from the selected tile to all other tiles. Debug.Log("Testing LOS"); if (this.selectedTile == null) { return; } foreach (BattleTile tile in this.tiles) { bool canSee = this.TestLOS(this.selectedTile, tile); DebugDrawers.SpawnLine( this.selectedTile.transform.position, tile.transform.position, canSee ? Color.green : Color.red, 2f ); } } else if (hardInput.GetKeyDown("Test pathing")) { Debug.Log("Testing pathing"); if (this.selectedTile == null || this.hoveredTile == null) { return; } if (this.selectedTile.mech) { this.pathNetwork.SetNodeEnabled(this.selectedTile, true); } PathingResult result = this.pathNetwork.FindPath( this.selectedTile, this.hoveredTile, true ); if (this.selectedTile.mech) { this.pathNetwork.SetNodeEnabled(this.selectedTile, false); } if (result.isValid) { Debug.Log(result.nodes.Count + " nodes in path " + result.distance + " units long."); } else { Debug.Log("Invalid path!"); } } else if (hardInput.GetKeyDown("Test saving")) { Debug.Log("Testing saving"); string jsonText = this.history.ToJSON(); string path = "TestSave.json"; using (StreamWriter sw = new StreamWriter(path)){ sw.WriteLine(jsonText); } Debug.Log("Wrote save to " + path); } }
public void Update() { // Test: path to a target mech, stop when we can see it and keep firing. BattleMech target = null; foreach (BattleTeam team in this.battle.teams) { foreach (BattleMech mech in team.mechs) { if (team != this.ourMech.team) { target = mech; break; } } } if (target == null) { return; } BattleTile ourTile = this.ourMech.tile; BattleTile targetTile = target.tile; bool canSeeTarget = this.battle.TestLOS(ourTile, targetTile); // TODO: this is really stupid this.battle.pathNetwork.SetNodeEnabled(ourTile, true); this.battle.pathNetwork.SetNodeEnabled(targetTile, true); PathingResult result = this.battle.pathNetwork.FindPath(ourTile, targetTile); this.battle.pathNetwork.SetNodeEnabled(ourTile, false); this.battle.pathNetwork.SetNodeEnabled(targetTile, false); if (result.isValid == false) { return; } BattleTile nextTile = (BattleTile)result.nodes[1]; if (canSeeTarget && result.distance <= 5) { var move = new BattleMove.StandingFire(); move.mechIndex = ourTile.index; move.targetMechIndex = targetTile.index; this.battle.ExecuteMove(move); } else { var move = new BattleMove.Move(); move.mechIndex = ourTile.index; move.newIndex = nextTile.index; if (canSeeTarget) { move.isFiring = true; move.targetMechIndex = targetTile.index; } else { move.isFiring = false; } this.battle.ExecuteMove(move); } this.battle.SetState(BattleState.EndOfAction); }