public void ApplyToDurationData(AbilityDurationData abilityDurationData, AbilityItemModel parentAbility) { abilityDurationData.OriginAbilityID = parentAbility.ID; abilityDurationData.PerTickAmount = int.Parse(PerTickAmount); abilityDurationData.TurnsPerTick = int.Parse(TurnsPerTick); abilityDurationData.MaxTicks = int.Parse(MaxTicks); abilityDurationData.AbilityEffectType = parentAbility.AbilityEffectType; abilityDurationData.AbilityTargetType = parentAbility.AbilityTargetType; }
private void processCombatantBehaviour(CombatantModel combatantModel) { // Advance all ability cooldowns for (int i = 0; i < combatantModel.AbilityItemModels.Length; i++) { combatantModel.AbilityItemModels[i].CoolDownTurnsElapsed++; } AbilityItemModel combatAbility = null; targets.Clear(); CombatActionModel combatActionModel = combatantModelToBehaviour[combatantModel].GetCombatAction(out combatAbility, ref targets); // If waiting, return if (combatActionModel.CombatActionType == CombatActionType.Wait) { return; } // if starting or canceling cast, append CombatActionModel and return if (combatActionModel.CombatActionType == CombatActionType.StartCastingAbility || combatActionModel.CombatActionType == CombatActionType.CancelCastingAbility) { combatActionsCollection[combatantModel.ID].Add(combatActionModel); return; } if (combatActionModel.CombatActionType != CombatActionType.ApplyAbility) { throw new Exception("Unexpected CombatActionType: " + combatActionModel.CombatActionType.ToString()); } // Append cast completion CombatActionModel combatActionsCollection[combatantModel.ID].Add(combatActionModel); // Restart ability cooldown combatAbility.CoolDownTurnsElapsed = 0; // Apply ability to targets and keep track of CombatActionModels bool isAbilityFriendly = combatAbility.IsFriendly(); for (int t = 0; t < targets.Count; t++) { CombatActionModel combatActionOnTarget; if (combatAbility.AbilityDurationType == AbilityDurationType.Immediate) // Handle ability with IMMEDIATE effect. { bool isCrit; int immediateAmountWithStatMods = getAbilityAmountWithStatMods(combatantModel, combatAbility.ImmediateAmout, combatAbility.IsSpellBased, out isCrit); if (isAbilityFriendly) { combatActionOnTarget = applyRegenAbilityEffectToCombatant(combatAbility.AbilityEffectType, combatAbility.ID, combatantModel.ID, immediateAmountWithStatMods, targets[t], 0, isCrit); } else { combatActionOnTarget = applyDamageAbilityEffectToCombatant(combatAbility.AbilityEffectType, combatAbility.ID, combatantModel.ID, immediateAmountWithStatMods, targets[t], 0, isCrit); } } else // Handle ability with DURATION effect { AbilityDurationData abilityDurationDataClone = combatAbility.AbilityDurationData.Clone(true); if (combatAbility.IsStatModifier()) { // Stat modifiers don't consider other stat modifiers. Ex: (if target has spell effect/damage debuff from // another modifier, we dont want another spell dmg debuff to cause exponential damage). targets[t].StatModifiersDeltas.AddModifier(abilityDurationDataClone.PerTickAmount, abilityDurationDataClone.AbilityEffectType); targets[t].StatModifierAbilityDurations.Add(abilityDurationDataClone); CombatActionType combatActionType = isAbilityFriendly ? CombatActionType.StatIncreasedByDurationAbility : CombatActionType.StatDecreasedByDurationAbility; combatActionOnTarget = new CombatActionModel( combatantModel.ID, combatActionType, combatAbility.ID, targets[t].ID, abilityDurationDataClone.PerTickAmount, abilityDurationDataClone.NumTurnsRemaining, false); } else { // Update clone's per tick value to consider the caster's spell/melee buffs/debuffs bool isCrit; int perTickAmountWithStatMods = getAbilityAmountWithStatMods( combatantModel, abilityDurationDataClone.PerTickAmount, combatAbility.IsSpellBased, out isCrit); abilityDurationDataClone.PerTickAmount = perTickAmountWithStatMods; abilityDurationDataClone.IsCrit = isCrit; AbilityDurationDataCollection abilityDurationCollection = isAbilityFriendly ? targets[t].RegenOverTimeAbilityDurations : targets[t].DamageOverTimeAbilityDurations; abilityDurationCollection.Add(abilityDurationDataClone); combatActionOnTarget = new CombatActionModel( combatantModel.ID, CombatActionType.AffectedByDurationAbility, combatAbility.ID, targets[t].ID, 0, abilityDurationDataClone.NumTurnsRemaining, isCrit); } } combatActionsCollection[targets[t].ID].Add(combatActionOnTarget); // If target has died then append death CombatActionModel if (!targets[t].IsAlive()) { combatActionsCollection[targets[t].ID].Add( new CombatActionModel(combatantModel.ID, CombatActionType.Death, combatAbility.ID, targets[t].ID, 0, 0, false)); } } }
private void onTurnElapsed() { // Update combatActionsCollection turn number combatActionsCollection.TurnNumber = TurnDispatcher.TurnNumber; Logging.Log.Info(">>>>>>> CoOpInstanceCombatController START TURN " + combatActionsCollection.TurnNumber); // If we're delaying, decrement delay turns and return if (delayStartTurns > 0) { Logging.Log.Info("CoOpInstanceCombatController delaying start for " + delayStartTurns + " turns..."); delayStartTurns--; return; } // Clear all CombatActionModels for all combatants for (int c = 0; c < allCombatants.Count; c++) { combatActionsCollection[allCombatants[c].ID].Clear(); } foreach (var kvp in teamIDToCombatantModel) { List <CombatantModel> teamCombatants = kvp.Value; for (int i = 0; i < teamCombatants.Count; i++) { CombatantModel combatantModel = teamCombatants[i]; if (!combatantModel.IsAlive()) { continue; } // Advance and apply regen duration abilities and keep track of CombatActionModels combatantModel.RegenOverTimeAbilityDurations.AdvanceAbilityDurations(tickedRegenAbilities); for (int r = 0; r < tickedRegenAbilities.Length && tickedRegenAbilities[r] != null; r++) { AbilityDurationData tickedRegenAbilityDuration = tickedRegenAbilities[r]; combatActionsCollection[combatantModel.ID].Add( applyRegenAbilityEffectToCombatant( tickedRegenAbilityDuration.AbilityEffectType, tickedRegenAbilityDuration.OriginAbilityID, tickedRegenAbilityDuration.OwnerCombatantID, tickedRegenAbilityDuration.PerTickAmount, combatantModel, tickedRegenAbilityDuration.NumTurnsRemaining, tickedRegenAbilityDuration.IsCrit)); } // Clean up any expired regen abilities and keep track of CombatActionModels combatantModel.RegenOverTimeAbilityDurations.RemoveAndResetExpired(expiredRegenAbilities); for (int rx = 0; rx < expiredRegenAbilities.Length && expiredRegenAbilities[rx] != null; rx++) { combatActionsCollection[combatantModel.ID].Add(new CombatActionModel(expiredRegenAbilities[rx].OwnerCombatantID, CombatActionType.ExpireAbility, expiredRegenAbilities[rx].OriginAbilityID, combatantModel.ID, 0, 0, false)); } // Advance and apply damage duration abilities and keep track of CombatActionModels combatantModel.DamageOverTimeAbilityDurations.AdvanceAbilityDurations(tickedDamageAbilities); for (int d = 0; d < tickedDamageAbilities.Length && tickedDamageAbilities[d] != null; d++) { AbilityDurationData tickedDamageAbilityDuration = tickedDamageAbilities[d]; combatActionsCollection[combatantModel.ID].Add( applyDamageAbilityEffectToCombatant( tickedDamageAbilityDuration.AbilityEffectType, tickedDamageAbilityDuration.OriginAbilityID, tickedDamageAbilityDuration.OwnerCombatantID, tickedDamageAbilityDuration.PerTickAmount, combatantModel, tickedDamageAbilityDuration.NumTurnsRemaining, tickedDamageAbilityDuration.IsCrit)); // If target has died then append CombatActionModel and break; if (!combatantModel.IsAlive()) { combatActionsCollection[combatantModel.ID].Add(new CombatActionModel(tickedDamageAbilities[d].OwnerCombatantID, CombatActionType.Death, tickedDamageAbilities[d].OriginAbilityID, combatantModel.ID, 0, 0, false)); break; } } if (!combatantModel.IsAlive()) { continue; } // Clean up any expired damage abilities and keep track of CombatActionModels combatantModel.DamageOverTimeAbilityDurations.RemoveAndResetExpired(expiredDamageAbilities); for (int dx = 0; dx < expiredDamageAbilities.Length && expiredDamageAbilities[dx] != null; dx++) { combatActionsCollection[combatantModel.ID].Add(new CombatActionModel(expiredDamageAbilities[dx].OwnerCombatantID, CombatActionType.ExpireAbility, expiredDamageAbilities[dx].OriginAbilityID, combatantModel.ID, 0, 0, false)); } // Advance stat modifier duration abilities // NOTE: no need to output per tick amount as stat modifiers only report their delta on application. combatantModel.StatModifierAbilityDurations.AdvanceAbilityDurations(tickedStatAbilities); // Expire and remove any stat modifier abilities and keep track of CombatActionModels combatantModel.StatModifierAbilityDurations.RemoveAndResetExpired(expiredStatAbilities); for (int sx = 0; sx < expiredStatAbilities.Length && expiredStatAbilities[sx] != null; sx++) { combatantModel.StatModifiersDeltas.RemoveModifier( expiredStatAbilities[sx].PerTickAmount, expiredStatAbilities[sx].AbilityEffectType); combatActionsCollection[combatantModel.ID].Add( new CombatActionModel(expiredStatAbilities[sx].OwnerCombatantID, CombatActionType.ExpireAbility, expiredStatAbilities[sx].OriginAbilityID, combatantModel.ID, 0, 0, false)); } // Process Combatant's behaviour processCombatantBehaviour(combatantModel); } } if (combatActionsCollection.HasEntries()) { CombatTurnCompleted(combatActionsCollection); } }