Exemplo n.º 1
0
        private async Task moveUnit(Unit unit, Coord target)
        {
            Coord unitCoords = battlefield.getUnitCoords(unit);

            battlefield.units[unitCoords.x, unitCoords.y] = null;
            battlefield.units[target.x, target.y]         = unit;

            Vector3 startPos = unit.gameObject.transform.position;
            Vector3 endPos   = Util.GridToWorld(
                new Vector3Int(target.x, target.y, battlefield.map[target.x, target.y].Count + 1)
                );

            //hack demo is in 15 hours i'm so tired let me sleep
            Vector3 offset = new Vector3(0, -2.2f, 0);

            if (unit is LightHorse || unit is HeavyHorse)
            {
                offset += new Vector3(0, -0.8f, 0);
            }
            endPos += offset;

            //Rotate to face target
            await rotateUnit(unit, target);

            //interpolate.
            float moveUnitProgress = 0.0f;

            while (moveUnitProgress < turnDelayMs)
            {
                //Slower at the start and end. a beautiful logistic curve.
                float progressPercent = 1 / (1 + Mathf.Pow((float)(Math.E), -4 * ((moveUnitProgress / turnDelayMs) - 0.5f)));

                unit.gameObject.transform.position = Vector3.Lerp(startPos, endPos, progressPercent);
                await Task.Delay(10);

                moveUnitProgress += 10;
            }
            //Just in case....
            unit.gameObject.transform.position = endPos;

            //Yes yes i know this is terrible.
            if (unit is RangedUnit)
            {
                unit.setHasAttackedThisTurn(true);
            }
        }
Exemplo n.º 2
0
        // Update is called once per frame
        async void Update()
        {
            switch (battleStage)
            {
            case BattleLoopStage.Initial:
                if (!cutscene.isRunning)
                {
                    CameraController.inputEnabled = true;
                    cutsceneCamera.enabled        = false;
                    mainCamera.enabled            = true;
                    advanceBattleStage();
                }
                break;

            case BattleLoopStage.Pick:
                advanceBattleStage();
                break;

            case BattleLoopStage.BattleLoopStart:
                advanceBattleStage();
                break;

            case BattleLoopStage.TurnChange:
                //If we've already entered this we're awaiting. Don't call it again every frame.
                if (!battleStageChanged)
                {
                    break;
                }
                battleStageChanged = false;

                currentCharacter    = (currentCharacter + 1) % level.characters.Length;
                turnPlayerText.text =
                    level.characters[currentCharacter].name + "'s turn\n" +
                    "Turns remaining:  " + (objective.maxHalfTurns - ((halfTurnsElapsed / 2) + 1));
                turnPlayerText.enabled       = true;
                turnChangeBackground.enabled = true;
                Util.setTimeout(advanceBattleStage, 1000);

                break;

            case BattleLoopStage.TurnChangeEnd:
                turnPlayerText.enabled       = false;
                turnChangeBackground.enabled = false;
                advanceBattleStage();
                break;

            case BattleLoopStage.UnitSelection:
                advanceBattleStage();
                break;

            case BattleLoopStage.ActionSelection:
                //If we've already entered this we're awaiting. Don't call it again every frame.
                if (!battleStageChanged)
                {
                    break;
                }
                battleStageChanged = false;

                //Character.getMove() is responsible for validation so we assume the move to be legal
                Move             move         = await level.characters[currentCharacter].getMove();
                Unit             ourUnit      = battlefield.units[move.from.x, move.from.y];
                IBattlefieldItem selectedItem = battlefield.battlefieldItemAt(move.to.x, move.to.y);

                if (selectedItem is Tile)
                {
                    //We selected a tile! lets move to it
                    moveUnit(ourUnit, move.to.x, move.to.y);

                    if (ourUnit.getTargets(move.to.x, move.to.y, battlefield, level.characters[currentCharacter]).Count == 0)
                    {
                        ourUnit.greyOut();
                    }
                }
                else if (selectedItem is Unit)
                {
                    //Targeted a hostile unit! fight!
                    Unit selectedUnit = selectedItem as Unit;

                    bool defenderDefeated = ourUnit.doBattleWith(
                        selectedUnit,
                        battlefield.map[move.to.x, move.to.y].Peek(),
                        battlefield);

                    await Task.Delay(TimeSpan.FromMilliseconds(250));

                    if (!defenderDefeated && (selectedItem is MeleeUnit) && (ourUnit is MeleeUnit))
                    {
                        //Counterattack applied only when both units are Melee
                        selectedUnit.doBattleWith(
                            ourUnit,
                            battlefield.map[move.from.x, move.from.y].Peek(),
                            battlefield);
                    }

                    ourUnit.setHasAttackedThisTurn(true);
                    await Task.Delay(TimeSpan.FromMilliseconds(250));
                }
                else
                {
                    Debug.LogWarning("Item of unrecognized type clicked on.");
                }

                checkWinAndLose();

                //If all of our units have moved advance. Otherwise, go back to unit selection.
                ourUnit.hasMovedThisTurn = true;
                if (battlefield.charactersUnits[level.characters[currentCharacter]].All(unit => {
                    //I know this looks inelegant but it avoid calling getUnitCoords if necessary
                    if (!unit.hasMovedThisTurn)
                    {
                        return(false);
                    }
                    else if (unit.getHasAttackedThisTurn())
                    {
                        return(true);
                    }
                    else
                    {
                        Coord coord = battlefield.getUnitCoords(unit);
                        return(unit.getTargets(coord.x, coord.y, battlefield, level.characters[currentCharacter]).Count == 0);
                    }
                }))
                {
                    advanceBattleStage();
                }
                else
                {
                    setBattleLoopStage(BattleLoopStage.UnitSelection);
                }

                break;

            case BattleLoopStage.EndTurn:
                //If we've already entered this we're awaiting. Don't call it again every frame.
                if (!battleStageChanged)
                {
                    break;
                }
                battleStageChanged = false;

                foreach (Unit unit in battlefield.charactersUnits[level.characters[currentCharacter]])
                {
                    unit.hasMovedThisTurn = false;
                    unit.setHasAttackedThisTurn(false);
                }

                bool endGame = checkWinAndLose();
                if (!endGame)
                {
                    advanceBattleStage();
                }

                halfTurnsElapsed++;

                break;
            }
        }
Exemplo n.º 3
0
        // Poor man's state machine. in retrospect i have no idea why i didn't use a proper one. oh well, next game.
        async void Update()
        {
            switch (battleStage)
            {
            case BattleLoopStage.Initial:
                if (!battleStageChanged)
                {
                    break;
                }
                battleStageChanged = false;

                playBgm();

                turnPlayerText.text =
                    "Battle objective:\n" +
                    objective.getName();
                turnPlayerText.enabled       = true;
                turnChangeBackground.enabled = true;
                await Task.Delay(3000);

                advanceBattleStage();
                break;

            case BattleLoopStage.Pick:
                advanceBattleStage();
                turnPlayerText.enabled       = false;
                turnChangeBackground.enabled = false;

                break;

            case BattleLoopStage.BattleLoopStart:
                if (!battleStageChanged)
                {
                    break;
                }
                battleStageChanged = false;
                //Check for cutscenes every start phase
                await runAppropriateCutscenes();

                advanceBattleStage();
                break;

            case BattleLoopStage.TurnChange:
                //If we've already entered this we're awaiting. Don't call it again every frame.
                if (!battleStageChanged)
                {
                    break;
                }
                battleStageChanged = false;

                currentCharacter    = (currentCharacter + 1) % level.characters.Length;
                turnPlayerText.text =
                    level.characters[currentCharacter].name + "'s turn\n" +
                    "Turns remaining:  " + (objective.maxHalfTurns - halfTurnsElapsed);
                turnPlayerText.enabled       = true;
                turnChangeBackground.enabled = true;

                await Task.Delay(1000);

                advanceBattleStage();
                break;

            case BattleLoopStage.TurnChangeEnd:
                turnPlayerText.enabled       = false;
                turnChangeBackground.enabled = false;
                advanceBattleStage();
                break;

            case BattleLoopStage.UnitSelection:
                advanceBattleStage();
                break;

            case BattleLoopStage.ActionSelection:
                //If we've already entered this we're awaiting. Don't call it again every frame.
                if (!battleStageChanged)
                {
                    break;
                }
                battleStageChanged = false;

                //The getMove function returns null if no move should be made,
                //possibly in the event of the selection loop being interrupted by a manually ended turn
                Move move = await level.characters[currentCharacter].getMove();
                //Since no move occurs, nothing else needs to be done this turn (since nothing changed).
                if (move == null)
                {
                    break;
                }

                Unit ourUnit = battlefield.units[move.from.x, move.from.y];

                if (ourUnit == null)
                {
                    Debug.LogWarning("In BattleControl.update(), a move originated from a nonexistent unit, probably due to an ended turn.");
                    break;
                }

                IBattlefieldItem selectedItem = battlefield.battlefieldItemAt(move.to.x, move.to.y);
                if (move.from.Equals(move.to))
                {
                    //This is the null move. just do nothing!
                    ourUnit.hasMovedThisTurn = true;
                    ourUnit.setHasAttackedThisTurn(true);
                    ourUnit.greyOut();
                }
                else if (selectedItem is Tile)
                {
                    //We selected a tile! lets move to it
                    await moveUnit(ourUnit, move.to);

                    if (ourUnit.getTargets(move.to.x, move.to.y, battlefield, level.characters[currentCharacter]).Count == 0)
                    {
                        ourUnit.greyOut();
                        ourUnit.setHasAttackedThisTurn(true);
                    }
                }
                else if (selectedItem is Unit)
                {
                    //Targeted a hostile unit! fight!
                    Unit selectedUnit = selectedItem as Unit;

                    await rotateUnit(ourUnit, battlefield.getUnitCoords(selectedUnit));

                    bool defenderDefeated = await ourUnit.doBattleWith(
                        selectedUnit,
                        battlefield.map[move.to.x, move.to.y].Peek(),
                        battlefield);

                    if (!defenderDefeated && (selectedItem is MeleeUnit) && (ourUnit is MeleeUnit))
                    {
                        await rotateUnit(selectedUnit, battlefield.getUnitCoords(ourUnit));

                        //Counterattack applied only when both units are Melee
                        await selectedUnit.doBattleWith(
                            ourUnit,
                            battlefield.map[move.from.x, move.from.y].Peek(),
                            battlefield);
                    }

                    //Re-grey model if needed... I'm regretting my desire to make the health ui manager stateless :p
                    if (ourUnit is HealerUnit)
                    {
                        if ((selectedUnit.hasMovedThisTurn &&
                             selectedUnit.getTargets(move.to.x, move.to.y, battlefield, level.characters[currentCharacter]).Count == 0) ||
                            selectedUnit.getHasAttackedThisTurn())
                        {
                            selectedUnit.greyOut();
                        }
                    }

                    ourUnit.setHasAttackedThisTurn(true);
                    // await Task.Delay(TimeSpan.FromMilliseconds(turnDelayMs));
                }
                else
                {
                    Debug.LogWarning("Item of unrecognized type clicked on.");
                }


                ourUnit.hasMovedThisTurn = true;

                await runAppropriateCutscenes();

                //Check if we eliminated the last unit.
                await checkWinAndLose();

                // Update AI capture point if Intercept mission
                if (objective is InterceptObjective)
                {
                    foreach (Character c in level.characters)
                    {
                        if (c.agent is DefendAgent)
                        {
                            (c.agent as DefendAgent).capturePoint = battlefield.getUnitCoords((objective as InterceptObjective).vips[0]);
                        }
                    }
                }

                //If all of our units have moved advance. Otherwise, go back to unit selection.
                if (battlefield.charactersUnits[level.characters[currentCharacter]].All(unit => {
                    //I know this looks inelegant but it avoid calling getUnitCoords if necessary
                    if (!unit.hasMovedThisTurn)
                    {
                        return(false);
                    }
                    else if (unit.getHasAttackedThisTurn())
                    {
                        return(true);
                    }
                    else
                    {
                        Coord coord = battlefield.getUnitCoords(unit);
                        return(unit.getTargets(coord.x, coord.y, battlefield, level.characters[currentCharacter]).Count == 0);
                    }
                }))
                {
                    advanceBattleStage();
                }
                else
                {
                    setBattleLoopStage(BattleLoopStage.UnitSelection);
                }

                break;

            case BattleLoopStage.EndTurn:
                //If we've already entered this we're awaiting. Don't call it again every frame.
                if (!battleStageChanged)
                {
                    break;
                }
                battleStageChanged = false;

                //Check cutscenes every end phase
                await runAppropriateCutscenes();

                foreach (Unit unit in battlefield.charactersUnits[level.characters[currentCharacter]])
                {
                    Coord coord = battlefield.getUnitCoords(unit);
                    Tile  tile  = battlefield.map[coord.x, coord.y].Peek();
                    await checkTile(tile, unit);

                    unit.hasMovedThisTurn = false;
                    unit.setHasAttackedThisTurn(false);
                }

                bool endGame = await checkWinAndLose();

                if (!endGame)
                {
                    advanceBattleStage();
                }

                halfTurnsElapsed++;

                break;
            }
        }