public BasicRule( ParsedRule parsedInfo, int branchOpenSymbol, int branchCloseSymbol) { _targetSymbolWithParameters = parsedInfo.coreSymbol; ruleGroupIndex = parsedInfo.ruleGroupIndex; possibleOutcomes = new RuleOutcome[] { new RuleOutcome(1, parsedInfo.replacementSymbols) }; conditionalChecker = parsedInfo.conditionalMatch; backwardsMatchBuilder = new SymbolSeriesPrefixBuilder(parsedInfo.backwardsMatch); forwardsMatchBuilder = new SymbolSeriesSuffixBuilder(parsedInfo.forwardsMatch); forwardsMatchBuilder.BuildGraphIndexes(branchOpenSymbol, branchCloseSymbol); CapturedLocalParameterCount = _targetSymbolWithParameters.parameterLength + backwardsMatchBuilder.targetSymbolSeries.Sum(x => x.parameterLength) + forwardsMatchBuilder.targetSymbolSeries.Sum(x => x.parameterLength); }
public void Should_match_extension_column() { //arrange var rule = new ParsedRule { IsColumnInExtensions = true, Column = "Location", RuleType = RuleType.Contains, Value = "Test value" }; var transaction = new BankTransaction { Extensions = new { Location = "Some test value" }.ToJson() }; //act var result = Sut.IsRuleMatch(rule, transaction); //assert result.Should().BeTrue(); }
// this whole procedure is just for debugging purposes // it prints the rule out to the Procon console private void print_parsed_rule(ParsedRule rule) { if (rule.comment) { WriteDebugInfo(String.Format("ProconRulz: Rule {0}: {1}", rule.id, rule.unparsed_rule)); return; } // read each rule variable, convert to string, and then print formatted string trigger_string = String.Format("On {0}:",Enum.GetName(typeof(TriggerEnum), rule.trigger)); string parts_string = (rule.parts == null || rule.parts.Count == 0) ? " CONTINUE;" : " "; foreach (PartClass p in rule.parts) { parts_string += p.ToString(); } WriteDebugInfo(String.Format("ProconRulz: Rule {0}: {1}{2}", rule.id, trigger_string, parts_string)); }
private bool parse_text(ref ParsedRule parsed_rule, string part, bool negated) { if (part.Length < 6) { parse_error("Text", parsed_rule.unparsed_rule); return false; } PartClass c = new PartClass(); c.part_type = PartEnum.Text; c.negated = negated; c.string_list = new List<string>(part.Substring(negated ? 9 : 5).ToLower().Split(new char[] { rulz_item_separator }, StringSplitOptions.RemoveEmptyEntries)); parsed_rule.parts.Add(c); return true; }
// count of spawned specializations on team private bool parse_teamspec(ref ParsedRule parsed_rule, string[] fragments, bool negated) { if (fragments.Length != (negated ? 4 : 3)) { parse_error("TeamSpec", parsed_rule.unparsed_rule); return false; } PartClass c = new PartClass(); c.part_type = PartEnum.TeamSpec; c.negated = negated; c.int1 = Int32.Parse(fragments[negated ? 3 : 2]); List<string> spec_keys = item_keys(fragments[negated ? 2 : 1]); foreach (string spec_key in spec_keys) { if (!specDefines.Contains(spec_key)) WriteConsole(String.Format("ProconRulz: ^1Warning, Specialization {0} not found in Procon (but you can still use the key in ProconRulz)", spec_key)); } c.string_list = spec_keys; parsed_rule.parts.Add(c); spawn_counts.watch(c.string_list); return true; }
// count of spawned Kits on team private bool parse_teamkit(ref ParsedRule parsed_rule, string[] fragments, bool negated) { if (fragments.Length != (negated ? 4 : 3)) { parse_error("TeamKit", parsed_rule.unparsed_rule); return false; } PartClass c = new PartClass(); c.part_type = PartEnum.TeamKit; c.negated = negated; try { c.int1 = Int32.Parse(fragments[negated ? 3 : 2]); c.string_list = item_keys(fragments[negated ? 2 : 1]); foreach (string kit_key in c.string_list) { try { Kits k = (Kits)Enum.Parse(typeof(Kits), kit_key, true); } catch (ArgumentException) { WriteConsole(String.Format("ProconRulz: ^1Warning, kit {0} not found in Procon (but you can still use the key in ProconRulz)", kit_key)); } } parsed_rule.parts.Add(c); spawn_counts.watch(c.string_list); } catch { parse_error("TeamKit", parsed_rule.unparsed_rule); return false; } return true; }
private bool parse_team(ref ParsedRule parsed_rule, string[] fragments, bool negated) { if (fragments.Length < (negated ? 3 : 2)) { parse_error("Team", parsed_rule.unparsed_rule); return false; } PartClass c = new PartClass(); c.part_type = PartEnum.Team; c.negated = negated; c.string_list = item_keys(fragments[negated ? 2 : 1].ToLower()); parsed_rule.parts.Add(c); return true; }
private bool parse_set(ref ParsedRule parsed_rule, string[] fragments) { if (fragments.Length < 3) { parse_error("Set", parsed_rule.unparsed_rule); return false; } PartClass p = new PartClass(); p.part_type = PartEnum.Set; p.negated = false; p.string_list.Add(fragments[1]); // string_list[0] = var_name string value = ""; for (int i = 2; i < fragments.Length; i++) value += fragments[i]; p.string_list.Add(value); //string_list[1] = value to assign p.has_count = has_a_count(p); parsed_rule.parts.Add(p); return true; }
// parse a single rule string e.g. "On Kill;Damage SniperRifle;Kill 300" // return 'true' if parsed successfully private bool parse_rule(ref ParsedRule parsed_rule, string rule_string) { if (rule_string == null || rule_string.Length < 4) { return false; } // only parse if this rule is not a comment if (rule_string[0] == '#') parsed_rule.comment = true; else { string parse_string; if (rule_string[0] == '+') { parse_string = ";" + rule_string.Substring(1); } else { parse_string = rule_string; } string[] parts = parse_string.Replace("%3b", ";").Split( new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string part in parts) { // note we use Trim() to take off leading/trailing whitespace from part if (!parse_part(ref parsed_rule, part.Trim(), false)) return false; } // loop to next part } // looping through rule parts completed - now add to list "parsed_rules" return true; }
private bool parse_headshot(ref ParsedRule parsed_rule, bool negated) { PartClass c = new PartClass(); c.part_type = PartEnum.Headshot; c.negated = negated; parsed_rule.parts.Add(c); return true; }
// Here we translate some convenience conditions into actual equivalents: // PlayerFirst -> Not PlayerCount 1 (i.e. player count is not > 1, i.e. count MUST be 1) // TeamFirst -> Not TeamCount 1 // ServerFirst -> Not ServerCount 1 // PlayerOnce -> Not Rate 2 100000 (tricky to explain... rule has NOT fired twice in 100000 seconds, // which is only true the FIRST time the rule fires for this player // because the time period is long enough that the second time it fires // will be inside the 100000 second window so the condition will fail // the second (and later) time. // This rule takes advantage of the fact that RATES continue across // new round starts. Rates reset for a player on a new round when they are // NOT online. Told you it was tricky). private bool parse_first(ref ParsedRule parsed_rule, string condition, bool negated) { PartClass p = new PartClass(); p.int1 = 1; // 1 for 'first's, will change to 2 for PlayerOnce... p.negated = !negated; // i.e. "Not PlayerFirst" -> "PlayerCount 1", i.e. the Not inverts switch (condition) { case "playerfirst": p.part_type = PartEnum.PlayerCount; break; case "teamfirst": p.part_type = PartEnum.TeamCount; break; case "serverfirst": p.part_type = PartEnum.ServerCount; break; case "playeronce": p.part_type = PartEnum.Rate; p.int1 = 2; // is 1 for the above conditions, change to 2 here p.int2 = 100000; // period for Rate set to 100000 seconds i.e. about a day break; } p.has_count = true; parsed_rule.parts.Add(p); return true; }
private bool parse_damage(ref ParsedRule parsed_rule, string[] fragments, bool negated) { if (fragments.Length < (negated ? 3 : 2)) { parse_error("Damage", parsed_rule.unparsed_rule); return false; } PartClass c = new PartClass(); c.part_type = PartEnum.Damage; c.negated = negated; if (fragments.Length == (negated ? 4 : 3)) try { c.int1 = Int32.Parse(fragments[negated ? 3 : 2]); } catch { parse_error("Damage", parsed_rule.unparsed_rule); return false; } try { c.string_list = item_keys(fragments[negated ? 2 : 1]); foreach (string damage_key in c.string_list) { try { DamageTypes d = (DamageTypes)Enum.Parse(typeof(DamageTypes), damage_key, true); } catch (ArgumentException) { WriteConsole(String.Format("ProconRulz: ^1Warning, damage {0} not found in Procon (but you can still use the key in ProconRulz)", damage_key)); } } parsed_rule.parts.Add(c); spawn_counts.watch(c.string_list); } catch { parse_error("Damage", parsed_rule.unparsed_rule); return false; } return true; }
private void assign_keywords(TriggerEnum trigger, ParsedRule rulex, string player_name, ref Dictionary<SubstEnum, string> keywords, Inventory inv, Kill k, string item) { // HERE's WHERE WE UPDATE THE SUBST KEYWORDS (and conditions can as well, // e.g. TargetPlayer) // this would be more efficient if I only updated the keywords that are // actually used in the rulz // update player count etc for this rule (for use of %c% parameter // or subsequent Count condition) if (trigger == TriggerEnum.Spawn) { keywords[SubstEnum.Kit] = kit_desc(item_key(inv.Kit)); keywords[SubstEnum.KitKey] = item_key(inv.Kit); // keywords[Weaponkey, Weapon, Damage, SpecKey, Spec] all set in OnPlaeyrSpawned } else if (trigger == TriggerEnum.Kill || trigger == TriggerEnum.TeamKill || trigger == TriggerEnum.Suicide || trigger == TriggerEnum.PlayerBlock ) { try { // we're in a 'kill' type event here // as far as I can tell, 'k.DamageType' usually contains // weapon key, but sometimes can be null // with BF3, k.Killer.SoldierName can be empty (null or ""?) if (k == null) return; string victim_name = (k.Victim == null) ? "No victim" : k.Victim.SoldierName; keywords[SubstEnum.Victim] = victim_name; string weapon_key = k.DamageType; Weapon weapon_used; try { if (weapon_key == null) weapon_used = null; else weapon_used = weaponDefines[weapon_key]; } catch { weapon_used = null; } string weapon_descr = weapon_desc(weapon_key); string damage; try { damage = (weapon_used == null) ? "No damage key" : item_key(weapon_used.Damage); } catch { damage = "No damage key"; } keywords[SubstEnum.Weapon] = weapon_descr; keywords[SubstEnum.WeaponKey] = weapon_key; keywords[SubstEnum.KitKey] = spawned_kit(player_name); keywords[SubstEnum.Kit] = kit_desc(spawned_kit(player_name)); keywords[SubstEnum.VictimKit] = kit_desc(spawned_kit(victim_name)); keywords[SubstEnum.VictimTeamKey] = players.team_id(victim_name); keywords[SubstEnum.VictimTeam] = team_name(players.team_id(victim_name)); keywords[SubstEnum.VictimCountry] = players.cname(victim_name); keywords[SubstEnum.VictimCountryKey] = players.ckey(victim_name); keywords[SubstEnum.Damage] = damage; keywords[SubstEnum.Range] = k.Distance.ToString("0.0"); keywords[SubstEnum.Headshot] = k.Headshot ? "Headshot" : ""; } catch (Exception ex) { WriteConsole("ProconRulz: recoverable exception in assign_keywords #2"); PrintException(ex); return; } } if (trigger == TriggerEnum.PlayerBlock) { keywords.Add(SubstEnum.BlockedItem, item); WriteDebugInfo(String.Format("ProconRulz: test_rule[{0}] is PlayerBlock event for [{1}] OK", player_name, item)); } }
public async Task <IEnumerable <BankTransaction> > FindBankTransactionsFitToRule(ParsedRule parsedRule, Guid userId) { var bankTransactions = await ruleAccess.GetBankTransactions(userId); return(bankTransactions.Where(bankTransaction => ruleMatchChecker.IsRuleMatch(parsedRule, bankTransaction))); }
private bool process_parts(ParsedRule rule, List<PartClass> parts, string player_name, ref Dictionary<SubstEnum, string> keywords, Kill k, string item) { PartClass current_part = null; try { bool playercount_updated = false; // we only update PlayerCount etc ONCE either after a successful // PlayerCount, or before the use of %c% etc // check each of the PARTS. // for each part in the rule, call process_part() foreach (PartClass p in parts) { current_part = p; // so we can display the part that caused exception if needed // see if we should update PlayerCount etc here // rule can by NULL if parts is a list of TargetActions if (rule != null && !playercount_updated && p.has_count) { update_counts(player_name, rule.id, ref keywords); playercount_updated = true; } // HERE IS WHERE WE LEAVE THE PROC AND RETURN FALSE IF A CONDITION FAILS if (!process_part(rule, p, player_name, k, item, ref keywords)) return false; WriteDebugInfo(String.Format("ProconRulz: process_parts [{0}] OK", player_name)); } return true; } catch (Exception ex) { WriteConsole("ProconRulz: recoverable exception in process_parts (ProconRulz will continue)"); WriteConsole("ProconRulz: Rule was: " + rule.unparsed_rule); if (current_part != null) { WriteConsole("ProconRulz: Rule part was: " + current_part.ToString()); } else { WriteConsole("ProconRulz: Rule part was null"); } PrintException(ex); return false; } }
// RULZ VARIABLE INCR, DECR, SET and TEST conditions private bool parse_incr(ref ParsedRule parsed_rule, string[] fragments) { if (fragments.Length != 2) { parse_error("Incr", parsed_rule.unparsed_rule); return false; } PartClass c = new PartClass(); c.part_type = PartEnum.Incr; c.negated = false; c.string_list.Add(fragments[1].ToLower()); parsed_rule.parts.Add(c); return true; }
public bool Equals(RuleAttribute other) { return((other != null) && ParsedRule.ToString().Equals(other.ParsedRule.ToString(), StringComparison.Ordinal)); }
private bool parse_map(ref ParsedRule parsed_rule, string part, bool negated) { if (part.Length < 5) { parse_error("Map", parsed_rule.unparsed_rule); return false; } PartClass c = new PartClass(); c.part_type = PartEnum.Map; c.negated = negated; c.string_list = negated ? item_keys(part.Substring(8).ToLower()) : item_keys(part.Substring(4).ToLower()); parsed_rule.parts.Add(c); return true; }
// Here is where we try and parse the list of unparsed rules that // have been read from the server_ip.cfg // Input is the List<string> unparsed_rules, as read from server_ip.cfg // Output is the List<ParsedRule> parsed_rules // each rule is split into parts, with each part split into fragments e.g. // "team attack;teamsize 8;kit recon 2;say No More Snipers!;kill" // the first part is "team attack" // the first fragment is "team" void parse_rules() { int rule_id = 1; // initialise first value of rule identifier // start with a default trigger of "On Spawn" and update as rulz with triggers are parsed rule_prefix = new ParsedRule(); string rule_string_buffer = "empty"; // used to hold current rule for WriteConsole in case of exception try { if (!plugin_enabled) return; //WriteLog(String.Format("ProconRulz: Parsing your rules")); parsed_rules.Clear(); // start with an empty list ParsedRule parsed_rule = new ParsedRule(); // start with blank parsed rule parsed_rule.id = rule_id++; bool first_rule = true; // Concatenate user rules from settings AND user rulz files List<string> all_unparsed = new List<string>(unparsed_rules); foreach (KeyValuePair<string, string[]> rulz in filez_rulz) { all_unparsed.AddRange(rulz.Value); } WriteConsole("ProconRulz: loading " + all_unparsed.Count.ToString() + " rulz"); foreach (string rule_string in all_unparsed) { rule_string_buffer = rule_string; WriteDebugInfo("ProconRulz: parsing " + rule_string); if ((rule_string.Length > 0 && rule_string[0] != '+') || rule_string.Length == 0) { // this is not a rule continuation, store accumulated rule if (!first_rule) { parsed_rules.Add(parsed_rule); // add previous rule WriteDebugInfo("ProconRulz: storing rule " + parsed_rule.id.ToString() + " as " + parsed_rule.unparsed_rule); parsed_rule = new ParsedRule(); // start new rule parsed_rule.trigger = TriggerEnum.Void; // we can check this to see if rule has trigger parsed_rule.id = rule_id++; } } if (parse_rule(ref parsed_rule, rule_string)) { first_rule = false; WriteDebugInfo("ProconRulz: parsed ok"); parsed_rule.unparsed_rule += rule_string; // if rule did NOT have an On trigger, prepend the rule_prefix... if (parsed_rule.trigger == TriggerEnum.Void) { parsed_rule.trigger = rule_prefix.trigger; List<PartClass> l = new List<PartClass>(); foreach (PartClass p in rule_prefix.parts) l.Add(p); foreach (PartClass p in parsed_rule.parts) l.Add(p); parsed_rule.parts = l; } else { // rule DID have a trigger, so use this rule as new rule_prefix... rule_prefix.trigger = parsed_rule.trigger; rule_prefix.parts = new List<PartClass>(parsed_rule.parts); } } } // loop to next rule if (!first_rule) // flush last rule { parsed_rules.Add(parsed_rule); WriteDebugInfo("ProconRulz: storing last rule " + parsed_rule.id.ToString() + " as " + parsed_rule.unparsed_rule); } WriteConsole(string.Format("ProconRulz: {0} rules loaded", rule_id-1)); // run 'On Init' rulz OnInit(); } catch (Exception ex) { WriteConsole(String.Format("^1ProconRulz: Exception occurred parsing your rules")); WriteConsole(String.Format("^1ProconRulz: rule string was: "+rule_string_buffer)); PrintException(ex); } }
private bool parse_mapmode(ref ParsedRule parsed_rule, string[] fragments, bool negated) { if (fragments.Length != (negated ? 3 : 2)) { parse_error("MapMode", parsed_rule.unparsed_rule); return false; } PartClass c = new PartClass(); c.part_type = PartEnum.MapMode; c.negated = negated; c.string_list = item_keys(fragments[negated ? 2 : 1]); parsed_rule.parts.Add(c); return true; }
// a player name can be extracted from the say text (into %t%) private bool parse_targetplayer(ref ParsedRule parsed_rule, string part, bool negated) { PartClass c = new PartClass(); c.part_type = PartEnum.TargetPlayer; c.negated = negated; if (part.Length > 12) c.string_list.Add(part.Substring(13)); parsed_rule.parts.Add(c); return true; }
// "Not <condition>" e.g. "Not Team Attack" // this implementation is inelegant - I should be recursively calling parse_part(...) private bool parse_not(ref ParsedRule parsed_rule, string[] fragments, string part) { if (fragments.Length < 2) { parse_error("Not", parsed_rule.unparsed_rule); return false; } switch (fragments[1].ToLower()) { case "if": return parse_test(ref parsed_rule, part, true); case "text": return parse_text(ref parsed_rule, part, true); case "headshot": return parse_headshot(ref parsed_rule, true); case "protected": return parse_protected(ref parsed_rule, true); case "targetplayer": return parse_targetplayer(ref parsed_rule, part, true); case "admin": return parse_admin(ref parsed_rule, true); case "admins": return parse_admins(ref parsed_rule, true); case "ping": return parse_ping(ref parsed_rule, fragments, true); case "team": return parse_team(ref parsed_rule, fragments, true); case "teamsize": return parse_teamsize(ref parsed_rule, fragments, true); case "map": return parse_map(ref parsed_rule, part, true); case "mapmode": return parse_mapmode(ref parsed_rule, fragments, true); case "kit": return parse_kit(ref parsed_rule, fragments, true); case "spec": return parse_spec(ref parsed_rule, fragments, true); case "weapon": return parse_weapon(ref parsed_rule, fragments, true); case "damage": return parse_damage(ref parsed_rule, fragments, true); case "teamkit": return parse_teamkit(ref parsed_rule, fragments, true); case "teamspec": return parse_teamspec(ref parsed_rule, fragments, true); case "teamweapon": return parse_teamweapon(ref parsed_rule, fragments, true); case "teamdamage": return parse_teamdamage(ref parsed_rule, fragments, true); case "range": return parse_range(ref parsed_rule, fragments, true); case "count": case "playercount": return parse_count(ref parsed_rule, fragments, true); case "teamcount": return parse_teamcount(ref parsed_rule, fragments, true); case "servercount": return parse_servercount(ref parsed_rule, fragments, true); case "playerfirst": case "teamfirst": case "serverfirst": case "playeronce": return parse_first(ref parsed_rule, fragments[1].ToLower(), true); case "rate": return parse_rate(ref parsed_rule, fragments, true); default: parse_error("Not", parsed_rule.unparsed_rule); break; } return false; }
private bool parse_teamcount(ref ParsedRule parsed_rule, string[] fragments, bool negated) { if (fragments.Length == (negated ? 3 : 2)) { PartClass p = new PartClass(); p.part_type = PartEnum.TeamCount; p.negated = negated; p.int1 = Int32.Parse(fragments[negated ? 2 : 1]); p.has_count = true; parsed_rule.parts.Add(p); return true; } parse_error("TeamCount", parsed_rule.unparsed_rule); return false; }
private bool parse_on(ref ParsedRule parsed_rule, string[] fragments) { //WriteDebugInfo(String.Format("ProconRulz: Parsing On")); if (fragments.Length!=2) { parse_error("On", parsed_rule.unparsed_rule); return false; } if (fragments[1].ToLower().StartsWith("roundover")) { parsed_rule.trigger = TriggerEnum.RoundOver; return true; } if (fragments[1].ToLower().StartsWith("round")) { parsed_rule.trigger = TriggerEnum.Round; return true; } if (fragments[1].ToLower().StartsWith("join")) { parsed_rule.trigger = TriggerEnum.Join; return true; } if (fragments[1].ToLower().StartsWith("leave")) { parsed_rule.trigger = TriggerEnum.Leave; return true; } if (fragments[1].ToLower().StartsWith("spawn")) { parsed_rule.trigger = TriggerEnum.Spawn; return true; } if (fragments[1].ToLower().StartsWith("kill")) { parsed_rule.trigger = TriggerEnum.Kill; return true; } if (fragments[1].ToLower().StartsWith("teamkill")) { parsed_rule.trigger = TriggerEnum.TeamKill; return true; } if (fragments[1].ToLower().StartsWith("suicide")) { parsed_rule.trigger = TriggerEnum.Suicide; return true; } if (fragments[1].ToLower().StartsWith("playerblock")) { parsed_rule.trigger = TriggerEnum.PlayerBlock; return true; } if (fragments[1].ToLower().StartsWith("say")) { parsed_rule.trigger = TriggerEnum.Say; return true; } if (fragments[1].ToLower().StartsWith("init")) { parsed_rule.trigger = TriggerEnum.Init; return true; } parse_error("On", parsed_rule.unparsed_rule); return false; }
private bool parse_teamsize(ref ParsedRule parsed_rule, string[] fragments, bool negated) { if (fragments.Length < (negated ? 3 : 2)) { parse_error("Teamsize", parsed_rule.unparsed_rule); return false; } PartClass c = new PartClass(); c.part_type = PartEnum.Teamsize; c.negated = negated; try { c.int1 = Int32.Parse(fragments[negated ? 2 : 1]); } catch { parse_error("Teamsize", parsed_rule.unparsed_rule); return false; } parsed_rule.parts.Add(c); return true; }
// parse a 'part' of a rule, e.g. "Damage SniperRifle" or "TargetAction Kill 300" // returns 'true' if parse succeeded private bool parse_part(ref ParsedRule parsed_rule, string part, bool target_action) { try { bool rule_fail = false; // flag used to skip rest of rule on a parse error bool parsed_int = false; // flag used to confirm a part format with optional int was parsed ok // create action to be added to parsed_rule if we need it PartClass new_action = new PartClass(); new_action.target_action = target_action; string[] fragments = quoted_split(part); // v40b update to allow quoted strings if (fragments == null || fragments.Length == 0) return true; switch (fragments[0].ToLower()) { // TRIGGER ("On Spawn" or "On Kill") case "on": // trigger the rule on Spawn or a Kill rule_fail = !parse_on(ref parsed_rule, fragments); break; // CONDITIONS: i.e. what is needed for this rule to fire case "headshot": // e.g. "Headshot" rule_fail = !parse_headshot(ref parsed_rule, false); break; case "protected": // e.g. "Protected" - this player is on reserved slots list rule_fail = !parse_protected(ref parsed_rule, false); break; case "admin": // e.g. "Admin" - this player is an admin rule_fail = !parse_admin(ref parsed_rule, false); break; case "admins": // e.g. "Admins" - admins are on the server rule_fail = !parse_admins(ref parsed_rule, false); break; case "team": // e.g. "Team Attack" or defend rule_fail = !parse_team(ref parsed_rule, fragments, false); break; case "ping": // e.g. "Ping 300" rule_fail = !parse_ping(ref parsed_rule, fragments, false); break; case "teamsize": // e.g. "Teamsize 8" this rule only applies to teams this small or smaller rule_fail = !parse_teamsize(ref parsed_rule, fragments, false); break; case "map": // e.g. "Map Oasis" this rule only applies to map oasis rule_fail = !parse_map(ref parsed_rule, part, false); break; case "mapmode": // e.g. "MapMode Rush" this rule only applies to maps in Rush mode rule_fail = !parse_mapmode(ref parsed_rule, fragments, false); break; case "kit": // e.g. "Kit Recon 2" - max 2 recons on the team rule_fail = !parse_kit(ref parsed_rule, fragments, false); break; case "weapon": // e.g. "Weapon AUG 3" rule_fail = !parse_weapon(ref parsed_rule, fragments, false); break; case "spec": // e.g. "Spec sp_vdamage 3" rule_fail = !parse_spec(ref parsed_rule, fragments, false); break; case "damage": // e.g. "Damage SniperRifle 8" rule_fail = !parse_damage(ref parsed_rule, fragments, false); break; case "teamkit": // e.g. "TeamKit Recon 2" - max 2 recons on the team rule_fail = !parse_teamkit(ref parsed_rule, fragments, false); break; case "teamweapon": // e.g. "TeamWeapon AUG 3" rule_fail = !parse_teamweapon(ref parsed_rule, fragments, false); break; case "teamspec": // e.g. "TeamSpec sp_vdamage 3" rule_fail = !parse_teamspec(ref parsed_rule, fragments, false); break; case "teamdamage": // e.g. "TeamDamage SniperRifle 8" rule_fail = !parse_teamdamage(ref parsed_rule, fragments, false); break; case "range": // e.g. "Range 100" rule_fail = !parse_range(ref parsed_rule, fragments, false); break; case "not": // e.g. "Not Damage SniperRifle" rule_fail = !parse_not(ref parsed_rule, fragments, part); break; case "count": // e.g. "Count 8" - how many times PLAYER can trigger this rule case "playercount": // e.g. "PlayerCount 8" - how many times PLAYER can trigger this rule rule_fail = !parse_count(ref parsed_rule, fragments, false); break; case "teamcount": // e.g. "TeamCount 8" - how many times TEAM can trigger this rule rule_fail = !parse_teamcount(ref parsed_rule, fragments, false); break; case "servercount": // e.g. "ServerCount 8" - how many times SERVER can trigger this rule rule_fail = !parse_servercount(ref parsed_rule, fragments, false); break; case "playerfirst": case "teamfirst": case "serverfirst": case "playeronce": rule_fail = !parse_first(ref parsed_rule, fragments[0].ToLower(), false); break; case "rate": // e.g. "Rate 5 20" this rule triggered 5 times in 20 seconds rule_fail = !parse_rate(ref parsed_rule, fragments, false); break; case "text": // e.g. "On Say;Text ofc;Yell OFc 4 Ever" rule_fail = !parse_text(ref parsed_rule, part, false); break; case "targetplayer": // e.g. "TargetPlayer" (extract playername from say text) rule_fail = !parse_targetplayer(ref parsed_rule, part, false); break; case "incr": // e.g. "Incr kill_count" rule_fail = !parse_incr(ref parsed_rule, fragments); break; case "decr": // e.g. "Decr kill_count" rule_fail = !parse_decr(ref parsed_rule, fragments); break; case "set": // e.g. "Set kill_count 0" rule_fail = !parse_set(ref parsed_rule, fragments); break; case "if": // e.g. "If kill_count > 7" rule_fail = !parse_test(ref parsed_rule, part, false); break; // ACTIONS i.e. what to do when conditions are true // ************************************************ case "say": // e.g. "Say No more Snipers!" if (part.Length < 5) { parse_error("Say", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.Say; new_action.string_list.Add(part.Substring(4)); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "playersay": // e.g. "PlayerSay No more Snipers!" if (part.Length < 11) { parse_error("PlayerSay", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.PlayerSay; new_action.string_list.Add(part.Substring(10)); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "squadsay": // e.g. "SquadSay No more Snipers!" if (part.Length < 10) { parse_error("SquadSay", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.SquadSay; new_action.string_list.Add(part.Substring(9)); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "teamsay": // e.g. "TeamSay No more Snipers!" if (part.Length < 9) { parse_error("TeamSay", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.TeamSay; new_action.string_list.Add(part.Substring(8)); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "victimsay": // e.g. "VictimSay You were killed by %p%, range %r%!" if (part.Length < 11) { parse_error("VictimSay", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.VictimSay; new_action.string_list.Add(part.Substring(10)); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "adminsay": // e.g. "AdminSay HACKER WARNING on %p% (5 headshots in 15 seconds)!!" if (part.Length < 10) { parse_error("AdminSay", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.AdminSay; new_action.string_list.Add(part.Substring(9)); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "yell": if (part.Length < 6) { parse_error("Yell", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.Yell; parsed_int = false; // assume parsing yell_delay fails try { new_action.int1 = Int32.Parse(fragments[1]); // try and pick up yell delay (seconds) new_action.string_list.Add(String.Join(" ", fragments, 2, fragments.Length-2 )); // rest of string parsed_int = true; } catch { } if (!parsed_int) // we didn't parse a yell delay so use default { new_action.int1 = yell_delay; new_action.string_list.Add(part.Substring(5)); } new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "playeryell": // e.g. "PlayerYell No more Snipers!" if (part.Length < 12) { parse_error("PlayerYell", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.PlayerYell; parsed_int = false; // assume parsing yell_delay fails try { new_action.int1 = Int32.Parse(fragments[1]); // try and pick up yell delay (seconds) new_action.string_list.Add(String.Join(" ", fragments, 2, fragments.Length-2 )); // rest of string parsed_int = true; } catch { } if (!parsed_int) // we didn't parse a yell delay so use default { new_action.int1 = yell_delay; new_action.string_list.Add(part.Substring(11)); } new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "squadyell": // e.g. "SquadYell No more Snipers!" if (part.Length < 11) { parse_error("SquadYell", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.SquadYell; parsed_int = false; // assume parsing yell_delay fails try { new_action.int1 = Int32.Parse(fragments[1]); // try and pick up yell delay (seconds) new_action.string_list.Add(String.Join(" ", fragments, 2, fragments.Length-2 )); // rest of string parsed_int = true; } catch { } if (!parsed_int) // we didn't parse a yell delay so use default { new_action.int1 = yell_delay; new_action.string_list.Add(part.Substring(10)); } new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "teamyell": // e.g. "TeamYell No more Snipers!" if (part.Length < 10) { parse_error("TeamYell", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.TeamYell; parsed_int = false; // assume parsing yell_delay fails try { new_action.int1 = Int32.Parse(fragments[1]); // try and pick up yell delay (seconds) new_action.string_list.Add(String.Join(" ", fragments, 2, fragments.Length-2 )); // rest of string parsed_int = true; } catch { } if (!parsed_int) // we didn't parse a yell delay so use default { new_action.int1 = yell_delay; new_action.string_list.Add(part.Substring(9)); } new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "log": if (part.Length < 5) { parse_error("Log", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.Log; new_action.string_list.Add(part.Substring(4)); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "all": // say and yell and log if (part.Length < 5) { parse_error("All", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.All; new_action.string_list.Add(part.Substring(4)); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "both": // say and yell if (part.Length < 6) { parse_error("Both", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.Both; new_action.string_list.Add(part.Substring(5)); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "playerboth": // say and yell to a player if (part.Length < 12) { parse_error("PlayerBoth", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.PlayerBoth; new_action.string_list.Add(part.Substring(11)); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "kill": // kill player that triggered this rule new_action.part_type = PartEnum.Kill; if (fragments.Length == 2) new_action.string_list.Add(fragments[1]); else new_action.string_list.Add(kill_delay.ToString()); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "kick": // kick player that triggered this rule new_action.part_type = PartEnum.Kick; if (fragments.Length >= 2) new_action.string_list.Add(part.Substring(5)); else new_action.string_list.Add("Kicked automatically"); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "ban": // ban player that triggered this rule new_action.part_type = PartEnum.Ban; if (fragments.Length >= 2) new_action.string_list.Add(part.Substring(4)); else new_action.string_list.Add("[%p%] Banned automatically"); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "tempban": // temp ban player that triggered this rule new_action.part_type = PartEnum.TempBan; // try and pick up number of seconds for ban from fragments[1] bool tempban_default = true; if (fragments.Length >= 2) try { new_action.int1 = Int32.Parse(fragments[1]); tempban_default = false; } catch { new_action.int1 = ban_delay; } else new_action.int1 = ban_delay; // now try and dig out message // "TempBan" or "TempBan 7777" if (fragments.Length == 1 || (!tempban_default && fragments.Length == 2)) { new_action.string_list.Add("[%p%] automatic temp ban"); } // TempBan <message> else if (tempban_default && fragments.Length >= 2) { new_action.string_list.Add(part.Substring(8)); } // TempBan <N> <message> else if (!tempban_default && fragments.Length > 2) { new_action.string_list.Add(part.Substring(8 + fragments[1].Length)); } else { parse_error("TempBan", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "pbban": // ban player that triggered this rule via PunkBuster new_action.part_type = PartEnum.PBBan; if (fragments.Length >= 2) new_action.string_list.Add(part.Substring(6)); else new_action.string_list.Add("[%p%] Banned automatically"); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "pbkick": // temp ban player that triggered this rule (i.e. kick with timeout via PunkBuster) new_action.part_type = PartEnum.PBKick; // try and pick up number of MINUTES for ban from fragments[1] bool pbkick_default = true; if (fragments.Length >= 2) try { new_action.int1 = Int32.Parse(fragments[1]); pbkick_default = false; } catch { new_action.int1 = 0; } // default is NO temp ban on PB kick else new_action.int1 = 0; // now try and dig out message // "PBKick" or "PBKick 77" if (fragments.Length == 1 || (!pbkick_default && fragments.Length == 2)) { new_action.string_list.Add("[%p%] automatic temp kick/ban"); } // PBKick <message> else if (pbkick_default && fragments.Length >= 2) { new_action.string_list.Add(part.Substring(7)); } // PBKick <N> <message> else if (!pbkick_default && fragments.Length > 2) { new_action.string_list.Add(part.Substring(7 + fragments[1].Length)); } else { parse_error("PBKick", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "playerblock": // block player name from using item new_action.part_type = PartEnum.PlayerBlock; if (fragments.Length == 2) new_action.string_list.Add(fragments[1]); // item key else new_action.string_list.Add("unknown"); parsed_rule.parts.Add(new_action); break; case "targetconfirm": // trigger previous TargetAction actions from this player if (fragments.Length != 1) parse_error("TargetConfirm", parsed_rule.unparsed_rule); new_action.part_type = PartEnum.TargetConfirm; new_action.string_list.Add(""); parsed_rule.parts.Add(new_action); break; case "targetcancel": // cancel previous TargetAction actions from this player if (fragments.Length != 1) parse_error("TargetCancel", parsed_rule.unparsed_rule); new_action.part_type = PartEnum.TargetCancel; new_action.string_list.Add(""); parsed_rule.parts.Add(new_action); break; case "targetaction": // store delayed actions on target from this player rule_fail = !parse_part(ref parsed_rule, part.Substring(13), true); break; case "exec": // e.g. "Exec levelVars.set level levels/mp_007gr vehiclesDisabled false" if (part.Length < 6) { parse_error("Execute", parsed_rule.unparsed_rule); rule_fail = true; break; } new_action.part_type = PartEnum.Execute; new_action.string_list.Add(part.Substring(5)); new_action.has_count = has_a_count(new_action); parsed_rule.parts.Add(new_action); break; case "continue": new_action.part_type = PartEnum.Continue; new_action.string_list.Add(""); parsed_rule.parts.Add(new_action); break; case "end": new_action.part_type = PartEnum.End; new_action.string_list.Add(""); parsed_rule.parts.Add(new_action); break; default: WriteConsole(String.Format("^1ProconRulz: Unrecognised rule {0}", parsed_rule.unparsed_rule)); rule_fail = true; break; } return !rule_fail; } catch (Exception ex) { WriteConsole(String.Format("^1ProconRulz: Exception occurred parsing your rules")); WriteConsole(String.Format("^1ProconRulz: Rule was \"{0}\"", parsed_rule.unparsed_rule)); WriteConsole(String.Format("^1ProconRulz: Part that failed was \"{0}\"", part)); PrintException(ex); return false; } }
private bool parse_test(ref ParsedRule parsed_rule, string part, bool negated) { string[] fragments_in = quoted_split(part); string[] fragments; // if "Not If" then shift fragments left List<string> fragment_list = new List<string>(); if (negated) { for (int i = 1; i < fragments_in.Length; i++) { fragment_list.Add(fragments_in[i]); } fragments = fragment_list.ToArray(); } else fragments = fragments_in; // OK we got to here with the fragments being "If", val1, condition, val2 if (fragments.Length < 4) { parse_error("Bad If condition", parsed_rule.unparsed_rule); return false; } int condition_index = 0; for (int i = 1; i < fragments.Length; i++) { if (fragments[i] == "=" || fragments[i] == "!=" || fragments[i] == "==" || fragments[i] == "<>" || fragments[i] == ">" || fragments[i] == "<" || fragments[i] == ">=" || fragments[i] == "=>" || fragments[i] == "<=" || fragments[i] == "=<" || fragments[i].ToLower() == "contains" || fragments[i].ToLower() == "word" ) { condition_index = i; break; } } if (condition_index == 0) { parse_error("If condition has bad comparison operator", parsed_rule.unparsed_rule); return false; } PartClass p = new PartClass(); p.part_type = PartEnum.Test; p.negated = negated; string condition_part = ""; for (int i = 1; i < condition_index; i++) { condition_part += fragments[i]; } p.string_list.Add(condition_part); p.string_list.Add(fragments[condition_index]); condition_part = ""; for (int i = condition_index + 1; i < fragments.Length; i++) { condition_part += fragments[i]; } p.string_list.Add(condition_part); p.has_count = has_a_count(p); parsed_rule.parts.Add(p); return true; }
// this player is on reserved slots list private bool parse_protected(ref ParsedRule parsed_rule, bool negated) { PartClass c = new PartClass(); c.part_type = PartEnum.Protected; c.negated = negated; parsed_rule.parts.Add(c); return true; }
// updated to allow '&' char in weapon key instead of a space // this is complicated by the fact that weapon keys can // INCLUDE SPACES (thankyou EA) eg "M1A1 Thompson" and heli weapons // Weapon AUG // Not Weapon AUG // Weapon AUG 3 // Not Weapon AUG 3 // Weapon M1A1 Thompson // Weapon M1A1 Thompson 3 // Not Weapon M1A1 Thompson // Not Weapon M1A1 Thompson 3 // multiple weapon keys can be separated with rulz_item_separator E.g. Weapon SMAW,RPG-7 private bool parse_weapon(ref ParsedRule parsed_rule, string[] fragments, bool negated) { //WriteConsole(String.Format("rule {0}", parsed_rule.unparsed_rule)); //WriteConsole(String.Format("length {0}, negated {1}", fragments.Length, negated)); //WriteConsole(String.Format("fragments {0}", String.Join("---",fragments))); if (fragments.Length < (negated ? 3 : 2)) { parse_error("Weapon", parsed_rule.unparsed_rule); return false; } // ok lets try and figure out what we've got in the rule List<string> weapon_keys = item_keys((negated ? fragments[2] : fragments[1])); // try and make a count out of the last fragment int weapon_count = -1; try { weapon_count = Int32.Parse(fragments[fragments.Length - 1]); } catch { } //WriteConsole(String.Format("weapon_count {0}", weapon_count)); PartClass c = new PartClass(); c.part_type = PartEnum.Weapon; c.negated = negated; if (weapon_count > -1) c.int1 = weapon_count; foreach (string weapon_key in weapon_keys) { if (!weaponDefines.Contains(weapon_key)) WriteConsole(String.Format("ProconRulz: ^1Warning, weapon {0} not found in Procon (but you can still use the key in ProconRulz)", weapon_key)); } c.string_list = weapon_keys; parsed_rule.parts.Add(c); spawn_counts.watch(c.string_list); //else { parse_error("Weapon", parsed_rule.unparsed_rule); return false; } return true; }
// range of the kill private bool parse_range(ref ParsedRule parsed_rule, string[] fragments, bool negated) { if (fragments.Length == (negated ? 3 : 2)) { PartClass c = new PartClass(); c.part_type = PartEnum.Range; c.negated = negated; c.int1 = Int32.Parse(fragments[negated ? 2 : 1]); parsed_rule.parts.Add(c); return true; } parse_error("Range", parsed_rule.unparsed_rule); return false; }
// check a condition (e.g. "Kit Recon 2") in the current rule // rule.trigger is already confirmed to be the current event (e.g. Kill, Spawn) private bool process_part(ParsedRule rule, PartClass p, string player_name, Kill k, string msg, ref Dictionary<SubstEnum, string> keywords) { // CATCH EXCEPTIONS try { string not = p.negated ? "Not " : ""; bool return_val = false; string player_team_id = "-1"; if (keywords.ContainsKey(SubstEnum.PlayerTeamKey)) { player_team_id = keywords[SubstEnum.PlayerTeamKey]; } switch (p.part_type) { case PartEnum.Headshot: // test "Headshot" return_val = p.negated ? !k.Headshot : k.Headshot; WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}Headshot {2}", player_name, not, return_val)); return return_val; case PartEnum.Protected: // test player os on reserved slots list return_val = p.negated ? !protected_player(player_name) : protected_player(player_name); WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}Protected {2}", player_name, not, return_val)); return return_val; case PartEnum.Admin: // test player is an admin return_val = p.negated ? !is_admin(player_name) : is_admin(player_name); WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}Admin {2}", player_name, not, return_val)); return return_val; case PartEnum.Admins: // test if any admins are currently online return_val = p.negated ? !admins_present() : admins_present(); WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}Admins {2}", player_name, not, return_val)); return return_val; case PartEnum.Team: // test "team attack|defend" bool team_matches = team_match(p.string_list, player_team_id); return_val = p.negated ? !team_matches : team_matches; WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}Actual team {2} versus {3} {4}", player_name, not, team_key(player_team_id), keys_join(p.string_list), return_val)); return return_val; case PartEnum.Ping: // test "Ping N" int current_ping = players.ping(player_name); return_val = p.negated ? current_ping < p.int1 : current_ping >= p.int1; WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}Ping {2} versus limit {3} {4}", player_name, not, current_ping, p.int1, return_val)); return return_val; case PartEnum.Teamsize: // test "Teamsize N" int min_teamsize = players.min_teamsize(); return_val = p.negated ? min_teamsize > p.int1 : min_teamsize <= p.int1; WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}Teamsize {2} versus limit {3} {4}", player_name, not, min_teamsize, p.int1, return_val)); return return_val; case PartEnum.Map: // test map name or filename contains string1 return_val = p.negated ? !map_match(p.string_list) : map_match(p.string_list); WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}Actual map {2} versus {3} {4}", player_name, not, current_map.PublicLevelName + " or " + current_map.FileName, keys_join(p.string_list), return_val)); return return_val; case PartEnum.MapMode: // test "mapmode rush|conquest" return_val = p.negated ? !mapmode_match(p.string_list) : mapmode_match(p.string_list); WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}Actual MapMode {2} versus {3} {4}", player_name, not, current_map_mode, keys_join(p.string_list), return_val)); return return_val; case PartEnum.Kit: case PartEnum.Weapon: case PartEnum.Spec: case PartEnum.Damage: // test "Kit Recon 2" etc if (rule.trigger == TriggerEnum.Spawn) // will check *player* item as well as team count (spawn) return test_spawn_item(player_team_id, player_name, p); else // will also test kill item for TeamKill and Suicide return test_kill_item(k, p); case PartEnum.TeamKit: case PartEnum.TeamWeapon: case PartEnum.TeamSpec: case PartEnum.TeamDamage: return test_spawned_count(player_team_id, p); case PartEnum.Range: // test "Range > int1" return_val = p.negated ? !(k.Distance < p.int1) : k.Distance > p.int1; WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}range {2} > limit {3} {4}", player_name, not, k.Distance, p.int1, return_val)); return return_val; case PartEnum.Count: case PartEnum.PlayerCount: // check how many times PLAYER has triggered this rule int current_count = count_rule(player_name, rule.id); bool count_valid = current_count > p.int1; return_val = p.negated ? !count_valid : count_valid; WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}PlayerCount {2} (actual {3}) {4}", player_name, not, p.int1, current_count, return_val)); return return_val; case PartEnum.TeamCount: // check how many times PLAYER'S TEAM has triggered this rule int current_team_count = count_team_rule(players.team_id(player_name), rule.id); bool count_team_valid = current_team_count > p.int1; return_val = p.negated ? !count_team_valid : count_team_valid; WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}TeamCount {2} (actual {3}) {4}", player_name, not, p.int1, current_team_count, return_val)); return return_val; case PartEnum.ServerCount: // check how many times ALL PLAYERS have triggered this rule int current_server_count = count_server_rule(rule.id); bool count_server_valid = current_server_count > p.int1; return_val = p.negated ? !count_server_valid : count_server_valid; WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}ServerCount {2} (Actual {3}) {4}", player_name, not, p.int1, current_server_count, return_val)); return return_val; case PartEnum.Rate: // check condition "Rate X Y" i.e. X hits on this rule in Y seconds add_rate(player_name, rule.id); bool rate_valid = check_rate(player_name, rule.id, p.int1, p.int2); return p.negated ? !rate_valid : rate_valid; case PartEnum.Text: // check say text condition e.g. "Text ofc 4 ever,teamwork is everything" int index = -1; foreach (string t in p.string_list) { index = msg.ToLower().IndexOf(t.ToLower()); if (index >= 0 && keywords[SubstEnum.Text] != null && keywords[SubstEnum.Text].Length >= t.Length + 2) { // set up TargetText for TargetPlayer keywords[SubstEnum.TargetText] = keywords[SubstEnum.Text].Substring(index + t.Length).Trim(); } if (index >= 0) break; } return_val = p.negated ? index == -1 : index != -1; WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}text {2} {3}", player_name, not, keys_join(p.string_list), return_val)); return return_val; case PartEnum.TargetPlayer: // check TargetPlayer condition, i.e. can we extract a playername from the say text // updated from v33 for find_players to return a LIST of player names // if only ONE playername matches, then automatically add TargetConfirm to action list... WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] checking TargetPlayer[{1}]", player_name, keywords[SubstEnum.Text])); List<string> player_names = new List<string>(); if (p.string_list != null && p.string_list.Count != 0) { // here the 'targettext' is specified in the rule e.g. "TargetPlayer bambam" player_names = find_players(rulz_vars.replace_vars(player_name, replace_keys(p.string_list[0], keywords))); } // note only 1 playername is allowed in condition else // because it could contain rulz_item_separator { // here the targettext from a previous "Text" condition will be used // if successful, we will modify TargetText to be AFTER the playername match string string[] t_words = null; if (keywords.ContainsKey(SubstEnum.TargetText)) { t_words = quoted_split(keywords[SubstEnum.TargetText]); } if (t_words != null && t_words.Length > 0) { player_names = find_players(t_words[0]); if (keywords[SubstEnum.TargetText].Length - t_words[0].Length > 1) { keywords[SubstEnum.TargetText] = keywords[SubstEnum.TargetText].Substring(t_words[0].Length + 1); } else { keywords[SubstEnum.TargetText] = ""; } } } return_val = p.negated ? player_names.Count == 0 : player_names.Count == 1; keywords[SubstEnum.Target] = player_names.Count == 0 ? "" : player_names[0]; WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1}TargetPlayer {2} {3} with {4}", player_name, not, keys_join(p.string_list), return_val, String.Join(",", player_names.ToArray()))); return return_val; case PartEnum.Set: // set rulz variable rulz_vars.set_value(player_name, p.string_list[0], p.string_list[1], keywords); WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] Set {1} {2}", player_name, keys_join(p.string_list), true)); return true; // set always succeeds case PartEnum.Incr: rulz_vars.incr(player_name, p.string_list[0], keywords); WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] Increment {1} {2}", player_name, p.string_list[0], true)); return true; // Incr always succeeds case PartEnum.Decr: rulz_vars.decr(player_name, p.string_list[0], keywords); WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] Decrement {1} {2}", player_name, p.string_list[0], true)); return true; // Decr always succeeds case PartEnum.Test: // aka If // test var1 compare var2 (c.string_list[0..2]) WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] IF %c% is [{1}]", player_name, keywords[SubstEnum.Count])); return_val = rulz_vars.test(player_name, p.string_list[0], p.string_list[1], p.string_list[2], keywords); if (p.negated) return_val = !return_val; WriteDebugInfo(String.Format("ProconRulz: check_condition [{0}] {1} IF {2} {3}", player_name, not, keys_join(p.string_list), return_val)); return return_val; default: take_action(player_name, p, keywords); return true; } } catch (Exception ex) { WriteConsole("ProconRulz: recoverable exception in process_part (ProconRulz will continue...)"); WriteConsole("ProconRulz: process_part rule.unparsed_rule = " + ((rule == null) ? "(rule=null)" : (rule.unparsed_rule == null ? "(null)" : "[" + rule.unparsed_rule + "]") ) ); WriteConsole("ProconRulz: process_part player_name = " + ((player_name == null) ? "(null)" :"[" + player_name + "]")); WriteConsole("ProconRulz: process_part p.part_type = " + ((p == null) ? "(p=null)" : (p.part_type == null ? "(null)" : p.part_type.ToString()) ) ); WriteConsole("ProconRulz: process_part k.Killer.SoldierName = " + ((k == null) ? "(k=null)" : ((k.Killer == null) ? "(k.Killer=null)" : ((k.Killer.SoldierName==null) ? "(null)" : ("["+k.Killer.SoldierName+"]")) ) ) ); PrintException(ex); return false; } }
private bool parse_rate(ref ParsedRule parsed_rule, string[] fragments, bool negated) { PartClass p = new PartClass(); if (fragments.Length != (negated ? 4 : 3)) { parse_error("Rate", parsed_rule.unparsed_rule); return false; } try { p.part_type = PartEnum.Rate; p.negated = negated; p.int1 = Int32.Parse(fragments[negated ? 2 : 1]); p.int2 = Int32.Parse(fragments[negated ? 3 : 2]); } catch { parse_error("Rate", parsed_rule.unparsed_rule); return false; } parsed_rule.parts.Add(p); return true; }
// test a rule (we have already confirmed Spawn or Kill trigger is true) // will return 'true' if the rule is applied private bool process_rule(TriggerEnum trigger, ParsedRule rule, string player_name, ref Dictionary<SubstEnum, string> keywords, Inventory inv, Kill k, string item) { WriteDebugInfo(String.Format("ProconRulz: process_rule[{0}] with event {1}", player_name, Enum.GetName(typeof(TriggerEnum), trigger))); // CATCH EXCEPTIONS try { List<PartClass> parts = new List<PartClass>(rule.parts); if (trigger == TriggerEnum.Say) keywords[SubstEnum.Text] = item; // Populate the Counts AS IF THIS RULE SUCCEEDED so conditions can use them keywords[SubstEnum.ServerCount] = count_server_rule(rule.id).ToString() + 1; keywords[SubstEnum.Count] = count_rule(player_name, rule.id).ToString() + 1; keywords[SubstEnum.TeamCount] = count_team_rule(players.team_id(player_name), rule.id).ToString() + 1; // populate the 'keywords' dictionary assign_keywords(trigger, rule, player_name, ref keywords, inv, k, item); if (!process_parts(rule, parts, player_name, ref keywords, k, item)) { WriteDebugInfo(String.Format("ProconRulz: process_rule[{0}] in rule [{1}] tests NEGATIVE", player_name, rule.unparsed_rule)); return false; } WriteDebugInfo(String.Format("ProconRulz: process_rule[{0}] in rule [{1}] all conditions OK", player_name, rule.unparsed_rule)); // return 'true' to quit rulz checks after this rule // if rule contains End, Kill, Kick, TempBan, Ban unless it contains Continue. return end_rulz(parts); } catch (Exception ex) { WriteConsole("ProconRulz: recoverable exception in test_rule_and_exec(" + rule.unparsed_rule + ")"); PrintException(ex); return false; } }
public override int GetHashCode() { return(ParsedRule.ToString().GetHashCode()); }