public SodaScriptTrigger AddDefaultTrigger() { SodaScriptTrigger dt = AddTrigger(SodaScriptTarget.ENEMY, SodaScriptCondition.WEAKEST); dt.SetSkill(SodaScriptSkillCategory.DEFAULT); return(dt); }
public SodaScriptTrigger AddTrigger(SodaScriptTarget inTarget, SodaScriptCondition inCondition, SodaScriptComparison inComparison = SodaScriptComparison.EQUALS, string inCompareValue = "") { SodaScriptTrigger t = new SodaScriptTrigger(inTarget, inCondition, inComparison, inCompareValue); triggers.Add(t); return(t); }
public void DeleteTrigger(SodaScriptTrigger inTrigger) { if (!triggers.Contains(inTrigger)) { throw new Exception("Soda script does not contain requested trigger"); } triggers.Remove(inTrigger); }
public float GetNormalizedListPositionForTrigger(SodaScriptTrigger inTrigger) { float triggerIndex = GetTriggerIndex(inTrigger); if (triggerIndex == 0) { return(0); } return((triggerIndex + 1) / triggers.Count); }
//Validate ensures that the chosen combination of target, condition, comparison, value, and skill all make sense. //In the case of an invalid combination, default values are chosen public void ValidateTrigger(SodaScriptTrigger inTrigger) { if (!triggers.Contains(inTrigger)) { throw new Exception("Soda script was asked to validate a trigger it doesn't contain"); } //VALIDATE PRIMARY CONDITION if (!IsAllowedConditionForTarget(inTrigger.condition, inTrigger.target)) { inTrigger.condition = GetDefaultConditionForTarget(inTrigger.target); } if (ConditionRequiresAComparison(inTrigger.condition)) { if (!IsAllowedComparisonForCondition(inTrigger.comparison, inTrigger.condition)) { inTrigger.comparison = GetDefaultComparisonForCondition(inTrigger.condition); } if (!IsAllowedComparisonValueForCondition(inTrigger.compareValue, inTrigger.condition)) { inTrigger.compareValue = GetDefaultCompareValueForCondition(inTrigger.condition); } } //VALIDATE SECONDARY CONDITION if (!IsAllowedConditionForTarget(inTrigger.secondaryCondition, inTrigger.target)) { inTrigger.secondaryCondition = GetDefaultConditionForTarget(inTrigger.target); } if (ConditionRequiresAComparison(inTrigger.secondaryCondition)) { if (!IsAllowedComparisonForCondition(inTrigger.secondaryComparison, inTrigger.secondaryCondition)) { inTrigger.secondaryComparison = GetDefaultComparisonForCondition(inTrigger.secondaryCondition); } if (!IsAllowedComparisonValueForCondition(inTrigger.secondaryCompareValue, inTrigger.secondaryCondition)) { inTrigger.secondaryCompareValue = GetDefaultCompareValueForCondition(inTrigger.secondaryCondition); } } //VALIDATE CHOSEN SKILL ID (IF THERE IS ONE) if (inTrigger.skillCategory == SodaScriptSkillCategory.SPECIFIC) { if (!IsAllowedSkillIdForTarget(inTrigger.skillId, inTrigger.target)) { inTrigger.skillId = GetDefaultSkillIdForTarget(inTrigger.target); } } }
private int GetTriggerIndex(SodaScriptTrigger inTrigger) { for (int i = 0; i < triggers.Count; i++) { if (triggers[i] == inTrigger) { return(i); } } throw new Exception("Soda script does not contain requested trigger"); }
public SodaScriptTrigger GetCopy() { SodaScriptTrigger sst = new SodaScriptTrigger(target, condition, comparison, compareValue); sst.skillCategory = skillCategory; sst.skillId = skillId; sst.percentageChance = percentageChance; if (hasSecondaryCondition) { sst.hasSecondaryCondition = hasSecondaryCondition; sst.secondaryCondition = secondaryCondition; sst.secondaryComparison = secondaryComparison; sst.secondaryCompareValue = secondaryCompareValue; } return(sst); }
public void MoveTriggerDown(SodaScriptTrigger inTrigger) { if (!triggers.Contains(inTrigger)) { throw new Exception("Soda script does not contain requested trigger"); } if (triggers.Count == 1) { return; } int triggerIndex = GetTriggerIndex(inTrigger); if (triggerIndex == triggers.Count - 1) { return; } triggers.Remove(inTrigger); triggers.Insert(triggerIndex + 1, inTrigger); }
private bool EvalTrigger(SodaScriptTrigger inTrigger, SkillCommand inCommandToPopulate) { //is this a trigger with a percentage chance? if so start with that since it can save us processing time if (inTrigger.percentageChance < 100) { if (!Utils.PercentageChance(inTrigger.percentageChance)) { return(false); } } potentialTargets.Clear(); culledTargets.Clear(); CharacterData curTarget = null; if (inTrigger.target == SodaScriptTarget.SELF) { potentialTargets.Add(activeCharacter); } else if (inTrigger.target == SodaScriptTarget.ALLY) { for (int i = 0; i < ownTeam.members.Count; i++) { curTarget = ownTeam.members[i]; if (!curTarget.dead && curTarget != activeCharacter) { potentialTargets.Add(curTarget); } } } else if (inTrigger.target == SodaScriptTarget.ENEMY) { for (int i = 0; i < opposingTeam.members.Count; i++) { curTarget = opposingTeam.members[i]; if (!curTarget.dead) { potentialTargets.Add(curTarget); } } } //we might not even have a list of *potential* targets! (this would happen in a case when we try target an ally but we're the only member on the team) if (potentialTargets.Count == 0) { return(false); } //eval the condition on our list if (inTrigger.condition == SodaScriptCondition.ANY) { curTarget = potentialTargets.GetRandomElement(); potentialTargets.Clear(); potentialTargets.Add(curTarget); } else { //default to a normal eval EvalCondition(inTrigger.condition, inTrigger.comparison, inTrigger.compareValue, potentialTargets); } //exit if no potentials found yet if (potentialTargets.Count == 0) { return(false); } //do we have to check a secondary condition? if (inTrigger.hasSecondaryCondition) { EvalCondition(inTrigger.secondaryCondition, inTrigger.secondaryComparison, inTrigger.secondaryCompareValue, potentialTargets); } //did we find a valid target? if not, return false if (potentialTargets.Count == 0) { return(false); } //fix some issues when targetting self and requesting certain skill categories, turn into strongest *self* heal (avoids issues with first aid) if (inTrigger.target == SodaScriptTarget.SELF) { if (inTrigger.skillCategory == SodaScriptSkillCategory.STRONGEST_HEAL) { inTrigger.skillCategory = SodaScriptSkillCategory.STRONGEST_SELF_HEAL; } if (inTrigger.skillCategory == SodaScriptSkillCategory.ANY_BUFF) { inTrigger.skillCategory = SodaScriptSkillCategory.ANY_SELF_BUFF; } } //is the skill also valid? if not, return false if (inTrigger.skillCategory == SodaScriptSkillCategory.DEFAULT) { potentialSkill = activeCharacter.GetDefaultSkill(); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.SPECIFIC) { potentialSkill = Skill.GetSkill(inTrigger.skillId); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.ANY_NON_FRIENDLY_THAT_CONSUMES_MP) { potentialSkill = activeCharacter.GetAnyNonFriendlySkillThatUsesMP(); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.ANY_NON_FRIENDLY_THAT_DOESNT_CONSUME_MP) { potentialSkill = activeCharacter.GetAnyNonFriendlySkillThatDoesntUseMP(); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.ANY) { potentialSkill = activeCharacter.GetRandomUsableSkill(); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.STRONGEST_SELF_HEAL) { potentialSkill = activeCharacter.GetStrongestUsableHealSkill(false, true); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.STRONGEST_HEAL) { potentialSkill = activeCharacter.GetStrongestUsableHealSkill(false, false); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.STRONGEST_GROUP_HEAL) { potentialSkill = activeCharacter.GetStrongestUsableHealSkill(true, false); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.STRONGEST_ATTACK) { potentialSkill = activeCharacter.GetStrongestUsableDamageSkill(false); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.STRONGEST_GROUP_ATTACK) { potentialSkill = activeCharacter.GetStrongestUsableDamageSkill(true); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.STRONGEST_SINGLE_TARGET_ATTACK) { potentialSkill = activeCharacter.GetStrongestUsableDamageSkill(false, true); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.ANY_BUFF) { potentialSkill = activeCharacter.GetAnySkillThatBuffs(); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.ANY_SELF_BUFF) { potentialSkill = activeCharacter.GetAnySkillThatSelfBuffs(); } else if (inTrigger.skillCategory == SodaScriptSkillCategory.ANY_DEBUFF) { potentialSkill = activeCharacter.GetAnySkillThatDebuffs(); } else { throw new Exception("Skill category " + inTrigger.skillCategory + " is not supported"); } if (potentialSkill == null) { return(false); } if (!activeCharacter.CanUseSkill(potentialSkill.id)) { return(false); } //make sure we're not using a friendly skill on an enemy (unless it is DEFEND) if (inTrigger.target == SodaScriptTarget.ENEMY && potentialSkill.isFriendly && potentialSkill.id != SkillId.DEFEND) { return(false); } //make sure we're not using a damage skill on self or ally if ((inTrigger.target == SodaScriptTarget.ALLY || inTrigger.target == SodaScriptTarget.SELF) && !potentialSkill.isFriendly) { return(false); } //make sure if targeting self, chosen skill is allowed to self target if (inTrigger.target == SodaScriptTarget.SELF && !potentialSkill.allowsSelfTarget) { return(false); } //make sure not stealing from someone who has already been stolen from if ((potentialSkill.id == SkillId.PILFER || potentialSkill.id == SkillId.RANSACK) && potentialTargets[0].hasBeenStolenFrom) { return(false); } //don't try to transmute a target after we've already hit the limit of 1 successful transmute per battle (or if not a common enemy) if (potentialSkill.id == SkillId.TRANSMUTE) { bool battleIsBossOrMiniboss = (adventure.battleNumBasedOn10 == 5 || adventure.battleNumBasedOn10 == 10); if (adventure.battleManager.CurBattleTransmuteLimitReached() || battleIsBossOrMiniboss) { return(false); } } else if (potentialSkill.id == SkillId.FORETELL) { //don't try to foretell if the "force warp" flag is active for the current adventure if (adventure.forceWarpAtNextPaths) { return(false); } } //make sure an arena npc isn't using a banned skill if (activeCharacter.isArenaNpc && !potentialSkill.allowedForArenaNpcs) { return(false); } //make sure this team hasn't tried to heal itself too many times in a row if (potentialSkill.isHealing && ownTeam.HasReachedConsecutiveHealLimit()) { return(false); } //if we found a valid target and skill, populate the commmand and return true inCommandToPopulate.Reset(potentialSkill, activeCharacter); inCommandToPopulate.AddTarget(potentialTargets[0]); return(true); }
public static void CreateScripts() { scripts = new List <SodaScript>(); SodaScript script; SodaScriptTrigger trigger; //ENEMY script = new SodaScript(SCRIPT_DEFAULT_ENEMY); script._isReadonly = true; //testing trigger, use this to force a skill //trigger = script.AddTrigger(SodaScriptTarget.ENEMY, SodaScriptCondition.ANY); //trigger.SetSkill(SodaScriptSkillCategory.SPECIFIC, SkillId.STUN); trigger = script.AddTrigger(SodaScriptTarget.SELF, SodaScriptCondition.HP, SodaScriptComparison.LESS_THAN, "50"); trigger.SetSkill(SodaScriptSkillCategory.STRONGEST_HEAL); trigger.percentageChance = 70; trigger = script.AddTrigger(SodaScriptTarget.ALLY, SodaScriptCondition.HP, SodaScriptComparison.LESS_THAN, "60"); trigger.SetSkill(SodaScriptSkillCategory.STRONGEST_HEAL); trigger.percentageChance = 90; trigger = script.AddTrigger(SodaScriptTarget.SELF, SodaScriptCondition.STATUS, SodaScriptComparison.NOT_EQUALS, StatusEffectCategory.POSITIVE.ToString()); trigger.SetSkill(SodaScriptSkillCategory.ANY_SELF_BUFF); trigger.percentageChance = 70; //we can use this to attempt debuffs specifically, but any debuff is included in "any non friendly that consumes mp" trigger //trigger = script.AddTrigger(SodaScriptTarget.ENEMY, SodaScriptCondition.STATUS, SodaScriptComparison.NOT_EQUALS, StatusEffectCategory.NEGATIVE.ToString()); //trigger.SetSkill(SodaScriptSkillCategory.ANY_DEBUFF); trigger = script.AddTrigger(SodaScriptTarget.ENEMY, SodaScriptCondition.ANY); trigger.SetSkill(SodaScriptSkillCategory.ANY_NON_FRIENDLY_THAT_CONSUMES_MP); trigger.percentageChance = 25; trigger = script.AddTrigger(SodaScriptTarget.ENEMY, SodaScriptCondition.ANY); trigger.SetSkill(SodaScriptSkillCategory.ANY_NON_FRIENDLY_THAT_DOESNT_CONSUME_MP); trigger = script.AddTrigger(SodaScriptTarget.ENEMY, SodaScriptCondition.ANY); trigger.SetSkill(SodaScriptSkillCategory.DEFAULT); scripts.Add(script); //PLAYER script = new SodaScript(SCRIPT_DEFAULT_PLAYER); script._isReadonly = true; //testing trigger, use this to force a skill //trigger = script.AddTrigger(SodaScriptTarget.ENEMY, SodaScriptCondition.ANY); //trigger.SetSkill(SodaScriptSkillCategory.SPECIFIC, SkillId.STUN); trigger = script.AddTrigger(SodaScriptTarget.SELF, SodaScriptCondition.HP, SodaScriptComparison.LESS_THAN, "60"); trigger.SetSkill(SodaScriptSkillCategory.STRONGEST_HEAL); trigger = script.AddTrigger(SodaScriptTarget.ALLY, SodaScriptCondition.HP, SodaScriptComparison.LESS_THAN, "60"); trigger.SetSkill(SodaScriptSkillCategory.STRONGEST_HEAL); trigger = script.AddTrigger(SodaScriptTarget.ENEMY, SodaScriptCondition.TEAM_ALIVE, SodaScriptComparison.GREATER_THAN, "2"); trigger.SetSkill(SodaScriptSkillCategory.STRONGEST_GROUP_ATTACK); //50% chance to use a debuff skill on character with no debuffs trigger = script.AddTrigger(SodaScriptTarget.ENEMY, SodaScriptCondition.STATUS, SodaScriptComparison.NOT_EQUALS, StatusEffectCategory.NEGATIVE.ToString()); trigger.SetSkill(SodaScriptSkillCategory.ANY_DEBUFF); trigger.percentageChance = 50; trigger = script.AddTrigger(SodaScriptTarget.ENEMY, SodaScriptCondition.RANK, SodaScriptComparison.GREATER_THAN, EnemyRank.MBOS.ToString()); trigger.SetSecondaryCondition(SodaScriptCondition.HP, SodaScriptComparison.GREATER_THAN, "50"); trigger.SetSkill(SodaScriptSkillCategory.STRONGEST_SINGLE_TARGET_ATTACK); trigger = script.AddTrigger(SodaScriptTarget.ENEMY, SodaScriptCondition.ISNT_ORE); trigger.SetSecondaryCondition(SodaScriptCondition.WEAKEST); trigger.SetSkill(SodaScriptSkillCategory.DEFAULT); scripts.Add(script); //default trigger that will mostly be used by player scripts defaultTrigger = new SodaScriptTrigger(SodaScriptTarget.ENEMY, SodaScriptCondition.WEAKEST); defaultTrigger.SetSkill(SodaScriptSkillCategory.DEFAULT); //create some lists to limit user input to logically correct values USER_ALLOWED_TARGETS = new SodaScriptTarget[] { SodaScriptTarget.ENEMY, SodaScriptTarget.ALLY, SodaScriptTarget.SELF }; allowedConditionsForTarget = new Dictionary <SodaScriptTarget, SodaScriptCondition[]>(); allowedConditionsForTarget[SodaScriptTarget.ENEMY] = new SodaScriptCondition[] { SodaScriptCondition.WEAKEST, SodaScriptCondition.HP, SodaScriptCondition.MP, SodaScriptCondition.TEAM_ALIVE, SodaScriptCondition.TEAM_HP, SodaScriptCondition.RANK, SodaScriptCondition.IS_ORE, SodaScriptCondition.ISNT_ORE, SodaScriptCondition.BACK_IS_TURNED, SodaScriptCondition.BACK_ISNT_TURNED, SodaScriptCondition.STATUS, SodaScriptCondition.HAS_ESSENCE, SodaScriptCondition.NO_ESSENCE, SodaScriptCondition.IS_JANITOR, SodaScriptCondition.ISNT_JANITOR, SodaScriptCondition.ANY }; allowedConditionsForTarget[SodaScriptTarget.ALLY] = new SodaScriptCondition[] { SodaScriptCondition.WEAKEST, SodaScriptCondition.HP, SodaScriptCondition.MP, SodaScriptCondition.TEAM_ALIVE, SodaScriptCondition.TEAM_HP, SodaScriptCondition.STATUS, SodaScriptCondition.POSITION, SodaScriptCondition.ANY }; allowedConditionsForTarget[SodaScriptTarget.SELF] = new SodaScriptCondition[] { SodaScriptCondition.HP, SodaScriptCondition.MP, SodaScriptCondition.TEAM_ALIVE, SodaScriptCondition.TEAM_HP, SodaScriptCondition.STATUS }; conditionsThatRequireAComparison = new SodaScriptCondition[] { SodaScriptCondition.HP, SodaScriptCondition.MP, SodaScriptCondition.TEAM_ALIVE, SodaScriptCondition.TEAM_HP, SodaScriptCondition.RANK, SodaScriptCondition.STATUS, SodaScriptCondition.POSITION }; allComparisons = new SodaScriptComparison[] { SodaScriptComparison.GREATER_THAN, SodaScriptComparison.LESS_THAN, SodaScriptComparison.EQUALS, SodaScriptComparison.NOT_EQUALS }; justEqualsComparison = new SodaScriptComparison[] { SodaScriptComparison.EQUALS, SodaScriptComparison.NOT_EQUALS }; greaterOrLessThanComparison = new SodaScriptComparison[] { SodaScriptComparison.LESS_THAN, SodaScriptComparison.GREATER_THAN }; /********************************************************************************************************************** * DATA AND LABELS FOR COMPARISON VALUES THAT BELONG TO SPECIFIC CONDITIONS * ******************************************************************************************************************** */ string[] zeroToOneHundred = GenerateNumericDataList(0, 100, 5); string[] zeroToSix = GenerateNumericDataList(0, 6, 1); string[] oneToSix = GenerateNumericDataList(1, 6, 1); comparisonValuesForCondition = new Dictionary <SodaScriptCondition, string[]>(); comparisonValuesForCondition[SodaScriptCondition.HP] = zeroToOneHundred; comparisonValuesForCondition[SodaScriptCondition.MP] = zeroToOneHundred; comparisonValuesForCondition[SodaScriptCondition.TEAM_ALIVE] = zeroToSix; comparisonValuesForCondition[SodaScriptCondition.POSITION] = oneToSix; comparisonValuesForCondition[SodaScriptCondition.TEAM_HP] = zeroToOneHundred; EnemyRank[] ranks = new EnemyRank[] { EnemyRank.NORM, EnemyRank.MBOS, EnemyRank.BOSS, EnemyRank.DBOS }; comparisonValuesForCondition[SodaScriptCondition.RANK] = ranks.Select(d => d.ToString()).ToArray <string>(); StatusEffectCategory[] effectCategories = new StatusEffectCategory[] { StatusEffectCategory.POSITIVE, StatusEffectCategory.NEGATIVE, StatusEffectCategory.NONE }; comparisonValuesForCondition[SodaScriptCondition.STATUS] = effectCategories.Select(d => d.ToString()).ToArray <string>(); /********************************************************************************************************************** * SKILL CATEGORIES AND IDS * ******************************************************************************************************************** */ USER_ALLOWED_SKILL_CATEGORIES = new SodaScriptSkillCategory[] { SodaScriptSkillCategory.DEFAULT, SodaScriptSkillCategory.STRONGEST_ATTACK, SodaScriptSkillCategory.STRONGEST_GROUP_ATTACK, SodaScriptSkillCategory.STRONGEST_SINGLE_TARGET_ATTACK, SodaScriptSkillCategory.STRONGEST_HEAL, SodaScriptSkillCategory.STRONGEST_GROUP_HEAL, SodaScriptSkillCategory.ANY_BUFF, SodaScriptSkillCategory.ANY_DEBUFF, SodaScriptSkillCategory.ANY, SodaScriptSkillCategory.SPECIFIC }; //this array is locally scoped, we only use it to derive more specific lists //defend is not included here, it is a special case added later string[] userAllowedSkillIds = new string[] { SkillId.SWIFT_METAL, SkillId.BIOHAZARD, SkillId.FIRST_AID, SkillId.HEAL }; allowedSkillIdsForTarget = new Dictionary <SodaScriptTarget, string[]>(); //build out the lists/arrays Skill curSkill; List <string> allowedEnemySkillIds = new List <string>(); List <string> allowedAllySkillIds = new List <string>(); List <string> allowedSelfSkillIds = new List <string>(); for (int i = 0; i < userAllowedSkillIds.Length; i++) { curSkill = Skill.GetSkill(userAllowedSkillIds[i]); if (curSkill.isFriendly) { allowedAllySkillIds.Add(curSkill.id); if (curSkill.allowsSelfTarget) { allowedSelfSkillIds.Add(curSkill.id); } } else { allowedEnemySkillIds.Add(curSkill.id); } } //make sure to add "defend" for all categories allowedEnemySkillIds.Add(SkillId.DEFEND); allowedAllySkillIds.Add(SkillId.DEFEND); allowedSelfSkillIds.Add(SkillId.DEFEND); allowedSkillIdsForTarget[SodaScriptTarget.ENEMY] = allowedEnemySkillIds.ToArray <string>(); allowedSkillIdsForTarget[SodaScriptTarget.ALLY] = allowedAllySkillIds.ToArray <string>(); allowedSkillIdsForTarget[SodaScriptTarget.SELF] = allowedSelfSkillIds.ToArray <string>(); }