Esempio n. 1
0
    private void CheckForRegenProc()
    {
        turnsSinceRegenProc++;
        turnsUntilRegenProc = playerTeam.GetNumLivingMembers() + enemyTeam.GetNumLivingMembers();

        if (turnsSinceRegenProc >= turnsUntilRegenProc)
        {
            turnsSinceRegenProc = 0;
            Stats stats;

            for (int i = 0; i < charactersInBattle.Count; i++)
            {
                if (!charactersInBattle[i].dead)
                {
                    stats = charactersInBattle[i].stats;
                    long hpRegen = stats.Get(Stat.hp_regen);
                    long mpRegen = stats.Get(Stat.mp_regen);

                    //if character is magic inept, cancel any mp gain
                    if (charactersInBattle[i].HasSkill(SkillId.MAGIC_INEPT))
                    {
                        mpRegen = 0;
                    }

                    stats.Augment(Stat.hp, hpRegen);
                    stats.Augment(Stat.mp, mpRegen);

                    //enforcing limits here also takes care of any status effect damage
                    stats.EnforceLimits();

                    if (hpRegen > 0 || mpRegen > 0)
                    {
                        //broadcast this if at least one stat was regen'd
                        if (ERegenProc != null)
                        {
                            ERegenProc(charactersInBattle[i], hpRegen, mpRegen);
                        }
                    }
                }
            }
        }
    }
Esempio n. 2
0
    public void ResolveActiveSkillCommand()
    {
        SkillResult   curResult;
        CharacterData source = activeSkillCommand.source;
        CharacterData curTarget;

        currentSkillResults.Clear();

        //tally up damage that was reflected back at the source
        float accumulatedDamageReflected = 0;

        //tally up other properties to be used for stats
        float accumulatedHpChange       = 0;
        float accumulatedDamageAbsorbed = 0;
        uint  totalCrits       = 0;
        uint  totalEvades      = 0;
        uint  totalBackAttacks = 0;
        uint  totalDefends     = 0;

        //we take special actions for the defend and surrender skills
        if (activeSkillCommand.skill.id == SkillId.DEFEND)
        {
            source.isDefending = true;

            curResult = PoolManager.poolSkillResults.GetNext();
            curResult.Init(activeSkillCommand.skill, source, activeSkillCommand.targets[0]);
            currentSkillResults.Add(curResult);
        }
        else if (activeSkillCommand.skill.id == SkillId.SURRENDER)
        {
            //no action taken here; battle will be ended before anything meaningful can happen
        }
        else
        {
            for (int i = 0; i < activeSkillCommand.targets.Count; i++)
            {
                curTarget = activeSkillCommand.targets[i];
                curResult = activeSkillCommand.skill.GenerateResultToTarget(source, curTarget);
                Stats statChanges = curResult.statChanges;

                //make adjustments to the damage based on battle conditions AND the target's stats/conditions
                float hpChange = statChanges.Get(Stat.hp);

                //check this value here before any kind of absorb or defend is applied
                if (hpChange < 0)
                {
                    curResult.skillAttemptedToInflictDamage = true;
                }

                //REMOVED: add extra damage for huntress kill count, also increase damage if target is "marked"

                //check for special case where pickaxe deals bonus damage to something turned to stone
                if (curTarget.HasStatusEffect(StatusEffectType.STONE) && curResult.skill.id == SkillId.PICKAXE)
                {
                    hpChange *= GameContext.PICKAXE_AGAINST_STONE_MULTIPLIER;
                }

                //back attack? can't back attack mineable ore
                if (curResult.skill.canBackAttack && !curTarget.isOre)
                {
                    if (curTarget.BackIsTurnedTo(source) && !curTarget.IsImmuneToBackAttackBonus())
                    {
                        hpChange *= GameContext.BACK_ATTACK_MULTIPLIER;
                        curResult.wasBackAttack = true;
                        totalBackAttacks++;
                    }
                }

                //boost magic attack and phys attacks
                if (curResult.skill.IsType(SkillType.MAGICAL))
                {
                    long magBoost = source.stats.Get(Stat.magic_boost);
                    if (magBoost != 0)
                    {
                        float boostAmt = 1f + (magBoost / 100f);
                        hpChange *= boostAmt;
                    }

                    //hard max for group heal: cannot exceed half of target's max hp
                    if (curResult.skill.id == SkillId.GROUP_HEAL)
                    {
                        long max = curTarget.stats.Get(Stat.max_hp) / 2;
                        if (hpChange > max)
                        {
                            hpChange = max;
                        }
                    }
                }
                else if (curResult.skill.IsType(SkillType.PHYSICAL))
                {
                    long physBoost = source.stats.Get(Stat.phys_boost);
                    if (physBoost != 0)
                    {
                        float boostAmt = 1f + (physBoost / 100f);
                        hpChange *= boostAmt;
                    }
                }

                //crit. right now just manually check when using the strike skill. can't crit ore
                if (curResult.skill.id == SkillId.STRIKE && !curTarget.isOre)
                {
                    if (activeSkillCommand.source.RollPrimaryCritChance())
                    {
                        hpChange          = activeSkillCommand.source.GetPrimaryCritBonusAppliedToDamage(hpChange);
                        curResult.wasCrit = true;
                    }
                }

                if (curResult.wasDoubleCrit)
                {
                    totalCrits += 2;
                }
                else if (curResult.wasCrit)
                {
                    totalCrits++;
                }

                //apply super bonus crit damage?
                if (curResult.wasCrit || curResult.wasDoubleCrit)
                {
                    if (adventure.nextCritDamageBoostPercent > 0)
                    {
                        float boostAmt = 1f + (adventure.nextCritDamageBoostPercent / 100f);
                        hpChange *= boostAmt;
                        adventure.nextCritDamageBoostPercent = 0;
                    }
                }

                bool sourceMissed = false;
                bool targetEvaded = false;

                //additional checks for non-friendly skills: (evade, reduce damage, defend, etc)
                if (!curResult.skill.isFriendly)
                {
                    //damage absorb/reduce?
                    long reduction = curTarget.stats.Get(Stat.dmg_reduction);
                    if (curTarget.HasStatusEffect(StatusEffectType.STONE) && curResult.skill.id != SkillId.PICKAXE)
                    {
                        reduction += 50;
                    }

                    if (reduction != 0)
                    {
                        float prevHpChange = hpChange;
                        float reductionAmt = 1f - (reduction / 100f);
                        hpChange *= reductionAmt;
                        accumulatedDamageAbsorbed += (Math.Abs(prevHpChange) - Math.Abs(hpChange));
                    }

                    //is target defending? cut damage in half
                    if (curTarget.isDefending)
                    {
                        hpChange = hpChange / 2f;
                        totalDefends++;
                    }

                    //if the skill attempted to inflict damage but damage was reduced below 1, make it 1
                    if (curResult.skillAttemptedToInflictDamage && Math.Abs(hpChange) < 1)
                    {
                        hpChange = -1;
                    }

                    //did the source miss because they were confused?
                    sourceMissed = activeSkillCommand.source.HasStatusEffect(StatusEffectType.CONFUSION) && Utils.PercentageChance(75);

                    //did the target evade successfully? note that they would never evade a friendly attack
                    CharacterTeam targetsTeam = adventure.GetTeamForFaction(curTarget.curFaction);
                    bool          targetHasPartyProtection = curTarget.HasSkill(SkillId.PARTY_PROTECTION) && targetsTeam.GetNumLivingMembers() > 1;
                    if (curResult.source.curFaction != curResult.target.curFaction &&
                        (curTarget.PassesEvasionCheck() || targetHasPartyProtection))
                    {
                        targetEvaded = true;
                        totalEvades++;
                    }
                }

                //is target an ore? they take damage from the ore bust stat instead (min 1)
                if (curTarget.isOre && curResult.skillAttemptedToInflictDamage)
                {
                    //ore bust is a mixture of our existing ore bust stat plus whatever the attack itself specified. it's always at least 1
                    long oreBust = activeSkillCommand.source.stats.Get(Stat.ore_bust);
                    oreBust += statChanges.Get(Stat.ore_bust);
                    oreBust  = Math.Max(oreBust, 1);

                    //ore bust is stored as a positive number but must be converted to negative for damage
                    hpChange = -oreBust;
                }

                //finalize damage
                statChanges.Set(Stat.hp, (long)hpChange);

                //debug invincible characters
                if ((GameContext.DEBUG_INVINCIBLE_CHARACTERS && curTarget.curFaction == Faction.PLAYER) ||
                    (GameContext.DEBUG_INVINCIBLE_ENEMIES && curTarget.curFaction == Faction.ENEMY))
                {
                    if (statChanges.Get(Stat.hp) < 0)
                    {
                        statChanges.Set(Stat.hp, 0);
                    }
                }

                //this line will always knock the target down to 1hp
                //statChanges.Set(Stat.hp, -(curTarget.stats.Get(Stat.max_hp) - 1) );

                if (sourceMissed || targetEvaded)
                {
                    curResult.SetAsEvaded();
                }
                else
                {
                    curResult.ResolveEffects(adventure);

                    //resolve team effects for the first result (we only do this once because technically all results contain copies of the same team effects
                    if (i == 0)
                    {
                        curResult.ResolveTeamEffects(adventure);
                    }

                    //NOW THAT THE ATTACK CONNECTED AND WAS RESOLVED:
                    //tally it
                    accumulatedHpChange += hpChange;

                    //damage reflect
                    long damageReflect = curTarget.stats.Get(Stat.dmg_reflection);
                    if (damageReflect > 0 && hpChange < 0)
                    {
                        float reflectValue = (hpChange * (damageReflect / 100f));
                        accumulatedDamageReflected += Math.Abs(reflectValue);
                    }

                    //dark savior
                    if (curTarget.stats.Get(Stat.hp) == 0)
                    {
                        CharacterData savior = curTarget.GetCurTeam().GetMemberWhoCanUseDarkSaviorThatIsnt(curTarget);
                        if (savior != null)
                        {
                            curTarget.stats.Set(Stat.hp, 1);
                            savior.IncrementDarkSaviorUseCount();
                            curResult.invokedDarkSavior = true;
                        }
                    }

                    //was this a transmute? max one per battle, and must be a common enemy
                    if (curResult.transmutesTarget)
                    {
                        bool isCommonEnemy = false;
                        if (curResult.target is EnemyCharacterData && !curResult.target.isOre)
                        {
                            if (((EnemyCharacterData)curResult.target).rank == EnemyRank.NORM)
                            {
                                isCommonEnemy = true;
                            }
                        }

                        //special exception for the grill which currently counts as a NORM enemy
                        if (curResult.target.id == EnemyId.GRILL)
                        {
                            isCommonEnemy = false;
                        }

                        if (isCommonEnemy && !CurBattleTransmuteLimitReached())
                        {
                            curBattleTransmuteCount++;

                            CharacterData newOre = CharacterData.Get(adventure.curOreTable.RollSpawn()).GetCopy();
                            newOre.UnsetFlags(CharacterFlags.DEATH_OPTIONAL); //unset the death optional flag, since the player transmuted them on purpose (it would be weird to instantly end the battle now)
                            curResult.transmuteResult = newOre;

                            curTarget.GetCurTeam().TurnMemberInto(curTarget, newOre);

                            turnQueue.Remove(curTarget);
                            RefreshCharactersInBattleList();
                        }
                        else
                        {
                            curResult.transmutesTarget = false;
                            curResult.failedATransmute = true;
                        }
                    }
                }

                currentSkillResults.Add(curResult);
            }
        }

        //last step is to see if we create an additional result to send reflected damage back to the source
        if (accumulatedDamageReflected > 0 && !source.HasSkill(SkillId.PARTY_PROTECTION))
        {
            curResult = PoolManager.poolSkillResults.GetNext();
            curResult.Init(Skill.GetSkill(SkillId.STRIKE), source, source);
            curResult.statChanges.Set(Stat.hp, -accumulatedDamageReflected);
            curResult.ResolveEffects(adventure);
            currentSkillResults.Add(curResult);
        }

        //REMOVED: some local stat reporting to the save file

        if (ESkillResolved != null)
        {
            ESkillResolved(currentSkillResults);
        }
    }
Esempio n. 3
0
    //return true if this evals true for any target provided
    private void EvalCondition(SodaScriptCondition inCondition, SodaScriptComparison inComparison, string inCompareValue, List <CharacterData> inTargets)
    {
        CharacterData       targ;
        EnemyCharacterData  ecd;
        PlayerCharacterData pcd;

        culledTargets.Clear();

        if (inCondition == SodaScriptCondition.WEAKEST)
        {
            culledTargets.Add(GetLowestHpPercentTarget(inTargets));
        }
        else if (inCondition == SodaScriptCondition.TEAM_ALIVE)
        {
            targ = inTargets[0];
            CharacterTeam team = targ.IsInFaction(Faction.PLAYER) ? adventure.playerTeam : adventure.enemyTeam;
            if (EvalNumericComparison(team.GetNumLivingMembers(), int.Parse(inCompareValue), inComparison))
            {
                culledTargets.Add(targ);
            }
        }
        else if (inCondition == SodaScriptCondition.TEAM_HP)
        {
            targ = inTargets[0];
            CharacterTeam team = targ.IsInFaction(Faction.PLAYER) ? adventure.playerTeam : adventure.enemyTeam;
            if (EvalNumericComparison(team.GetTeamHPPercent(), int.Parse(inCompareValue), inComparison))
            {
                culledTargets.Add(targ);
            }
        }
        else if (inCondition == SodaScriptCondition.TEAM_NUM_BACK_TURNED)
        {
            targ = inTargets[0];
            CharacterTeam team          = targ.IsInFaction(Faction.PLAYER) ? adventure.playerTeam : adventure.enemyTeam;
            int           numBackTurned = team.GetNumMembersWithBackTurnedTo(activeCharacter);
            if (EvalNumericComparison(numBackTurned, int.Parse(inCompareValue), inComparison))
            {
                culledTargets.Add(targ);
            }
        }
        else
        {
            for (int i = 0; i < inTargets.Count; i++)
            {
                targ = inTargets[i];
                if (inCondition == SodaScriptCondition.HP)
                {
                    if (EvalNumericComparison(targ.GetHpPercent(), int.Parse(inCompareValue), inComparison))
                    {
                        culledTargets.Add(targ);
                    }
                }
                else if (inCondition == SodaScriptCondition.MP)
                {
                    if (EvalNumericComparison(targ.GetMpPercent(), int.Parse(inCompareValue), inComparison))
                    {
                        culledTargets.Add(targ);
                    }
                }
                else if (inCondition == SodaScriptCondition.POSITION)
                {
                    if (EvalNumericComparison(targ.originalOrderInTeam + 1, int.Parse(inCompareValue), inComparison))
                    {
                        culledTargets.Add(targ);
                    }
                }
                else if (inCondition == SodaScriptCondition.RANK)
                {
                    bool      foundRank  = false;
                    EnemyRank enemyRank  = EnemyRank.NORM;
                    EnemyRank parsedRank = (EnemyRank)Enum.Parse(typeof(EnemyRank), inCompareValue);

                    if (targ is EnemyCharacterData)
                    {
                        foundRank = true;
                        ecd       = (EnemyCharacterData)targ;
                        enemyRank = ecd.rank;
                    }
                    else if (targ.id == CharId.JANITOR)
                    {
                        foundRank = true;
                        enemyRank = EnemyRank.BOSS;
                    }

                    if (foundRank)
                    {
                        if (EvalNumericComparison((int)enemyRank, (int)parsedRank, inComparison))
                        {
                            culledTargets.Add(targ);
                        }
                    }
                }
                else if (inCondition == SodaScriptCondition.IS_ORE)
                {
                    if (targ.isOre)
                    {
                        culledTargets.Add(targ);
                    }
                }
                else if (inCondition == SodaScriptCondition.ISNT_ORE)
                {
                    if (!targ.isOre)
                    {
                        culledTargets.Add(targ);
                    }
                }
                else if (inCondition == SodaScriptCondition.IS_JANITOR)
                {
                    if (targ.id == CharId.JANITOR)
                    {
                        culledTargets.Add(targ);
                    }
                }
                else if (inCondition == SodaScriptCondition.ISNT_JANITOR)
                {
                    if (targ.id != CharId.JANITOR)
                    {
                        culledTargets.Add(targ);
                    }
                }
                else if (inCondition == SodaScriptCondition.BACK_IS_TURNED)
                {
                    if (!targ.isOre && targ.BackIsTurnedTo(activeCharacter))
                    {
                        culledTargets.Add(targ);
                    }
                }
                else if (inCondition == SodaScriptCondition.BACK_ISNT_TURNED)
                {
                    if (!targ.isOre && !targ.BackIsTurnedTo(activeCharacter))
                    {
                        culledTargets.Add(targ);
                    }
                }
                else if (inCondition == SodaScriptCondition.HAS_ESSENCE)
                {
                    if (targ.hasEssence)
                    {
                        culledTargets.Add(targ);
                    }
                }
                else if (inCondition == SodaScriptCondition.NO_ESSENCE)
                {
                    if (!targ.hasEssence)
                    {
                        culledTargets.Add(targ);
                    }
                }
                else if (inCondition == SodaScriptCondition.STATUS)
                {
                    StatusEffectCategory parsedCategory = (StatusEffectCategory)Enum.Parse(typeof(StatusEffectCategory), inCompareValue);
                    if (parsedCategory == StatusEffectCategory.POSITIVE)
                    {
                        bool hasPos = targ.HasPostiveStatusEffect();
                        if ((inComparison == SodaScriptComparison.EQUALS && hasPos) ||
                            (inComparison == SodaScriptComparison.NOT_EQUALS && !hasPos))
                        {
                            culledTargets.Add(targ);
                        }
                    }
                    else if (parsedCategory == StatusEffectCategory.NEGATIVE)
                    {
                        bool hasNeg = targ.HasNegativeStatusEffect();
                        if ((inComparison == SodaScriptComparison.EQUALS && hasNeg) ||
                            (inComparison == SodaScriptComparison.NOT_EQUALS && !hasNeg))
                        {
                            culledTargets.Add(targ);
                        }
                    }
                    else if (parsedCategory == StatusEffectCategory.NONE)
                    {
                        bool hasAny = targ.HasAnyStatusEffect();
                        if ((inComparison == SodaScriptComparison.EQUALS && !hasAny) ||
                            (inComparison == SodaScriptComparison.NOT_EQUALS && hasAny))
                        {
                            culledTargets.Add(targ);
                        }
                    }
                }
                else
                {
                    throw new Exception("Trigger condition " + inCondition + " is not supported as a condition");
                }
            }

            //do a final list sort based on the condition?
            if (inCondition == SodaScriptCondition.HP)
            {
                if (inComparison == SodaScriptComparison.GREATER_THAN)
                {
                    culledTargets = culledTargets.OrderByDescending(t => t.GetHpPercent()).ToList <CharacterData>();
                }
                else if (inComparison == SodaScriptComparison.LESS_THAN)
                {
                    culledTargets = culledTargets.OrderBy(t => t.GetHpPercent()).ToList <CharacterData>();
                }
            }
            else if (inCondition == SodaScriptCondition.MP)
            {
                if (inComparison == SodaScriptComparison.GREATER_THAN)
                {
                    culledTargets = culledTargets.OrderByDescending(t => t.GetMpPercent()).ToList <CharacterData>();
                }
                else if (inComparison == SodaScriptComparison.LESS_THAN)
                {
                    culledTargets = culledTargets.OrderBy(t => t.GetMpPercent()).ToList <CharacterData>();
                }
            }
        }

        potentialTargets.Clear();
        potentialTargets.AddRange(culledTargets);
    }