public List <MsgEvent> getThreats() { List <MsgEvent> reply = new List <MsgEvent>(); List <Unit> agents = new List <Unit>(); foreach (Unit u in map.units) { if (u.isEnthralled() && (!u.automated)) { agents.Add(u); } else { if (u.task is Task_Investigate) { reply.Add(new MsgEvent(u.getName() + " is investigating evidence at " + u.location.getName(), MsgEvent.LEVEL_ORANGE, false, u.location.hex)); } else if (u.task is Task_ShareSuspicions) { reply.Add(new MsgEvent(u.getName() + " is warning the noble at " + u.location.getName(), MsgEvent.LEVEL_ORANGE, false, u.location.hex)); } else if (u.task is Task_InvestigateNoble) { if (u.location.person() != null) { int level = MsgEvent.LEVEL_ORANGE; if (u.location.person().state == Person.personState.enthralled) { level = MsgEvent.LEVEL_RED; } reply.Add(new MsgEvent(u.getName() + " is investigating the noble at " + u.location.getName(), level, false, u.location.hex)); } } else if (u.task is Task_InvestigateNobleBasic) { if (u.location.person() != null) { int level = MsgEvent.LEVEL_YELLOW; if (u.location.person().state == Person.personState.enthralled) { level = MsgEvent.LEVEL_ORANGE; } reply.Add(new MsgEvent(u.getName() + " is investigating the noble at " + u.location.getName(), level, false, u.location.hex)); } } } } int[] suspicions = new int[agents.Count]; foreach (SocialGroup sg in map.socialGroups) { bool relevant = false; if (sg.hasEnthralled()) { relevant = true; } if (sg is Society) { Society soc = (Society)sg; if (soc.isDarkEmpire) { relevant = true; } foreach (Person p in soc.people) { if (p.state == Person.personState.enthralled || p.state == Person.personState.broken) { continue; } for (int i = 0; i < agents.Count; i++) { Unit u = agents[i]; if (u.person != null) { if (p.getRelation(u.person).suspicion > 0) { suspicions[i] += 1; } } } } if (soc.voteSession != null) { if (soc.voteSession.issue is VoteIssue_CondemnAgent) { VoteIssue_CondemnAgent issue = (VoteIssue_CondemnAgent)soc.voteSession.issue; if (issue.target.isEnthralled()) { reply.Add(new MsgEvent(soc.getName() + " is voting to condemn " + issue.target.getName(), MsgEvent.LEVEL_RED, false, issue.target.location.hex)); } } } } else { if (sg.isDark()) { relevant = true; } } if (relevant) { foreach (SocialGroup s2 in map.socialGroups) { if (s2 == sg) { continue; } if (s2 is Society) { Society soc = (Society)s2; Hex hex = null; if (soc.capital != null) { hex = soc.capital.hex; } if (soc.offensiveTarget == sg) { if (soc.posture == Society.militaryPosture.offensive) { int level = MsgEvent.LEVEL_RED; if (soc.currentMilitary < sg.currentMilitary * 0.75) { level = MsgEvent.LEVEL_ORANGE; } if (soc.currentMilitary < sg.currentMilitary * 0.25) { level = MsgEvent.LEVEL_YELLOW; } reply.Add(new MsgEvent(soc.getName() + " is offensive and targetting " + sg.getName(), MsgEvent.LEVEL_RED, false, hex)); if (soc.voteSession != null && soc.voteSession.issue is VoteIssue_DeclareWar) { reply.Add(new MsgEvent(soc.getName() + " is voting to declare war on " + sg.getName(), MsgEvent.LEVEL_RED, false, hex)); } } else { reply.Add(new MsgEvent(soc.getName() + " is targetting " + sg.getName(), MsgEvent.LEVEL_ORANGE, false, hex)); } } else { int nThreat = 0; foreach (Person p in soc.people) { ThreatItem t = p.getGreatestThreat(); if (t != null && t.group == sg) { nThreat += 1; } } if (nThreat > 0) { reply.Add(new MsgEvent(nThreat + " nobles from " + soc.getName() + " consider " + sg.getName() + " their greatest threat", MsgEvent.LEVEL_YELLOW, false, hex)); } } } } } } for (int i = 0; i < agents.Count; i++) { if (suspicions[i] > 0) { reply.Add(new MsgEvent(suspicions[i] + " nobles are suspicious of " + agents[i].getName(), MsgEvent.LEVEL_YELLOW, false)); } } return(reply); }
public VoteIssue proposeVotingIssue() { double bestU = 25; VoteIssue bestIssue = null; bool forcedBest = false; bool existFreeTitles = false; if (World.logging) { log.takeLine("Proposing vote on turn " + map.turn); } foreach (Location loc in map.locations) { if (loc.soc == society && loc.settlement != null && loc.settlement.title != null && loc.settlement.title.heldBy == null) { existFreeTitles = true; } } VoteIssue issue; //Unlanded titles can be distributed //Assignment of sovreign takes priority over any other voting, in the minds of the lords and ladies foreach (Title t in society.titles) { //Can assign an unassigned title, or hold routine elections bool canHold = t.heldBy == null || (map.turn - t.turnLastAssigned >= map.param.society_minTimeBetweenTitleReassignments); //You can hold emergency elections in the event of upcoming civil war if (society.data_societalStability < 0 && t == society.sovreign) { canHold = true; } if (!canHold) { continue; } issue = new VoteIssue_AssignTitle(society, this, t); if (t is Title_Sovreign) { if (society.titles.Count == 1) { //Everyone is eligible foreach (Person p in society.people) { VoteOption opt = new VoteOption(); opt.person = p; issue.options.Add(opt); } } else { //Only provincial rulers are elligible foreach (Person p in society.people) { if (p.titles.Count > 0) { VoteOption opt = new VoteOption(); opt.person = p; issue.options.Add(opt); } } } } else if (t is Title_ProvinceRuler) { Title_ProvinceRuler t2 = (Title_ProvinceRuler)t; //Nobles holding land in region are eligible foreach (Person p in society.people) { if (p == society.getSovreign()) { continue; } if (p.title_land != null && p.title_land.settlement.location.province == t2.province) { VoteOption opt = new VoteOption(); opt.person = p; issue.options.Add(opt); } } } if (issue.options.Count == 0) { continue; } foreach (VoteOption opt in issue.options) { //Random factor to prevent them all rushing a singular voting choice double localU = issue.computeUtility(this, opt, new List <ReasonMsg>()) * Eleven.random.NextDouble(); if (localU > bestU || (t == society.sovreign && t.heldBy == null))//Note we force them to vote on a sovereign if there is none { bestU = localU; bestIssue = issue; forcedBest = true; } } logVote(issue); } if (society.getSovreign() != null) { int oldestAssignment = 100000000; Location bestAssignable = null; /* * if (society.billsSinceLastSettlementAssignment > map.param.society_billsBetweenLandAssignments) * { * foreach (Location loc in map.locations) * { * if (loc.soc == this.society && loc.settlement != null && loc.settlement.title != null) * { * if (loc.settlement.lastAssigned < oldestAssignment) * { * oldestAssignment = loc.settlement.lastAssigned; * bestAssignable = loc; * } * } * } * } */ foreach (Location loc in map.locations) { //If there are unhanded out titles, only consider those. Else, check all. //Maybe they could be rearranged (handed out or simply swapped) in a way which could benefit you //if (loc.soc == society && loc.settlement != null && loc.settlement.title != null && ((!existFreeTitles) || (loc.settlement.title.heldBy == null))) //We're now stopping them suggesting this on places with existing nobles, as that lead to undue amounts of swapping // *now ammended to allow a single swap every N bills, AND it must be the last swapped one if (loc.soc == society && loc.settlement != null && loc.settlement.title != null && (loc.settlement.title.heldBy == null || loc == bestAssignable)) { //if (map.turn - loc.turnLastAssigned < Params.society_minTimeBetweenLocReassignments) { continue; } issue = new VoteIssue_AssignLandedTitle(society, this, loc.settlement.title); // if (lastProposedIssue != null && lastProposedIssue.GetType() == issue.GetType()) { break; }//Already seen this proposal, most likely. Make another or skip //Everyone is eligible foreach (Person p in society.people) { if (p.title_land != loc.settlement.title && p.title_land != null) { continue; } //Again, to prevent constant shuffling VoteOption opt = new VoteOption(); opt.person = p; issue.options.Add(opt); } foreach (VoteOption opt in issue.options) { //Random factor to prevent them all rushing a singular voting choice double localU = issue.computeUtility(this, opt, new List <ReasonMsg>()) * Eleven.random.NextDouble(); if (localU > bestU) { bestU = localU; bestIssue = issue; forcedBest = true; } } logVote(issue); } } if (society.needsToDecreasePopulation) { issue = new VoteIssue_DismissFromCourt(society, this); foreach (Person p in society.people) { if (p.title_land == null) { VoteOption opt = new VoteOption(); opt.person = p; issue.options.Add(opt); } } foreach (VoteOption opt in issue.options) { //Random factor to prevent them all rushing a singular voting choice double localU = issue.computeUtility(this, opt, new List <ReasonMsg>()) * Eleven.random.NextDouble(); if (localU > bestU) { bestU = localU; bestIssue = issue; forcedBest = true; } } } if (!forcedBest) { //Check to see if you want to economically rebalance the economy if (this.title_land != null) { HashSet <EconTrait> mine = new HashSet <EconTrait>(); HashSet <EconTrait> all = new HashSet <EconTrait>(); foreach (EconTrait trait in title_land.settlement.econTraits()) { mine.Add(trait); } foreach (Location loc in map.locations) { if (loc.soc == society && loc.settlement != null) { foreach (EconTrait trait in loc.settlement.econTraits()) { all.Add(trait); } } } foreach (EconTrait econ_from in all) { if (mine.Contains(econ_from)) { continue; } //Don't take from yourself foreach (EconTrait econ_to in mine) { issue = new VoteIssue_EconomicRebalancing(society, this, econ_from, econ_to); //Allow them to spam econ votes //if (lastProposedIssue != null && lastProposedIssue.GetType() == issue.GetType()) { break; }//Already seen this proposal, most likely. Make another or skip bool present = false; foreach (EconEffect effect in society.econEffects) { if (effect.from == econ_from && effect.to == econ_to) { present = true; } if (effect.to == econ_from && effect.from == econ_to) { present = true; } } if (present) { continue; } //We have our two options (one way or the other) VoteOption opt1 = new VoteOption(); opt1.econ_from = econ_from; opt1.econ_to = econ_to; issue.options.Add(opt1); VoteOption opt2 = new VoteOption(); opt2.econ_from = econ_to; opt2.econ_to = econ_from; issue.options.Add(opt2); foreach (VoteOption opt in issue.options) { //Random factor to prevent them all rushing a singular voting choice double localU = issue.computeUtility(this, opt, new List <ReasonMsg>()) * Eleven.random.NextDouble() * map.param.society_votingEconHiddenBiasMult; if (localU > bestU) { bestU = localU; bestIssue = issue; } } logVote(issue); } } } //Check to see if you want to alter offensive military targetting if (map.turn - society.lastOffensiveTargetSetting > 8) { issue = new VoteIssue_SetOffensiveTarget(society, this); foreach (SocialGroup neighbour in map.getExtendedNeighbours(society)) { VoteOption option = new VoteOption(); option.group = neighbour; issue.options.Add(option); } double localBest = 0; VoteOption voteOpt = null; foreach (VoteOption opt in issue.options) { //if (lastProposedIssue != null && lastProposedIssue.GetType() == issue.GetType()) { break; }//Already seen this proposal, most likely. Make another or skip //Random factor to prevent them all rushing a singular voting choice double localU = issue.computeUtility(this, opt, new List <ReasonMsg>()) * Eleven.random.NextDouble(); if (localU > localBest) { localBest = localU; voteOpt = opt; } } if (voteOpt != null && voteOpt.group != society.offensiveTarget && localBest > bestU) { bestU = localBest; bestIssue = issue; } logVote(issue); } { //Check to see if you want to alter defensive military targetting issue = new VoteIssue_SetDefensiveTarget(society, this); foreach (ThreatItem item in threatEvaluations) { if (item.group == null) { continue; } VoteOption option = new VoteOption(); option.group = item.group; issue.options.Add(option); } double localBest = 0; VoteOption voteOpt = null; foreach (VoteOption opt in issue.options) { //if (lastProposedIssue != null && lastProposedIssue.GetType() == issue.GetType()) { break; }//Already seen this proposal, most likely. Make another or skip //Random factor to prevent them all rushing a singular voting choice double localU = issue.computeUtility(this, opt, new List <ReasonMsg>()) * Eleven.random.NextDouble(); if (localU > localBest) { localBest = localU; voteOpt = opt; } } if (voteOpt != null && voteOpt.group != society.defensiveTarget && localBest > bestU) { bestU = localBest; bestIssue = issue; } logVote(issue); } { //Change military posture, to either improve defence, fix internal problems, or attack an enemy issue = new VoteIssue_MilitaryStance(society, this); for (int i = 0; i < 3; i++) { VoteOption opt = new VoteOption(); opt.index = i; issue.options.Add(opt); } double localBest = 0; VoteOption voteOpt = null; foreach (VoteOption opt in issue.options) { //if (lastProposedIssue != null && lastProposedIssue.GetType() == issue.GetType()) { break; }//Already seen this proposal, most likely. Make another or skip //Random factor to prevent them all rushing a singular voting choice double localU = issue.computeUtility(this, opt, new List <ReasonMsg>()) * Eleven.random.NextDouble(); if (localU > localBest) { localBest = localU; voteOpt = opt; } } int ourIndex = 0; if (society.posture == Society.militaryPosture.defensive) { ourIndex = 0; } if (society.posture == Society.militaryPosture.offensive) { ourIndex = 1; } if (society.posture == Society.militaryPosture.introverted) { ourIndex = 2; } if (voteOpt != null && voteOpt.index != ourIndex && localBest > bestU) { bestU = localBest; bestIssue = issue; } logVote(issue); } //Check to see if you want to declare war //You need to be in offensive posture to be allowed to do so if (society.offensiveTarget != null && society.posture == Society.militaryPosture.offensive && society.getRel(society.offensiveTarget).state != DipRel.dipState.war) { issue = new VoteIssue_DeclareWar(society, society.offensiveTarget, this); VoteOption option_0 = new VoteOption(); option_0.index = 0; issue.options.Add(option_0); VoteOption option_1 = new VoteOption(); option_1.index = 1; issue.options.Add(option_1); //if (lastProposedIssue != null && lastProposedIssue.GetType() == issue.GetType()) { break; }//Already seen this proposal, most likely. Make another or skip //Random factor to prevent them all rushing a singular voting choice double uWar = issue.computeUtility(this, option_1, new List <ReasonMsg>()); double uPeace = issue.computeUtility(this, option_0, new List <ReasonMsg>()); double localU = (uWar - uPeace) * Eleven.random.NextDouble(); if (localU > bestU) { bestU = localU; bestIssue = issue; } logVote(issue); } //Check to see if you want to defensively vassalise yourself //You need to be in defensive posture to be allowed to do so if (society.offensiveTarget != null && society.posture == Society.militaryPosture.defensive && (society.isAtWar() == false)) { foreach (SocialGroup sg in society.getNeighbours()) { if (sg is Society == false) { continue; } if (sg == this.society) { continue; } Society other = (Society)sg; if (other.defensiveTarget == this.society.defensiveTarget) { issue = new VoteIssue_Vassalise(society, other, this); VoteOption option_0 = new VoteOption(); option_0.index = 0; issue.options.Add(option_0); VoteOption option_1 = new VoteOption(); option_1.index = 1; issue.options.Add(option_1); //if (lastProposedIssue != null && lastProposedIssue.GetType() == issue.GetType()) { break; }//Already seen this proposal, most likely. Make another or skip //Random factor to prevent them all rushing a singular voting choice double localU = issue.computeUtility(this, option_1, new List <ReasonMsg>()) * Eleven.random.NextDouble(); if (localU > bestU) { bestU = localU; bestIssue = issue; } logVote(issue); } } } if (map.param.useAwareness == 1 && map.worldPanic >= map.param.panic_canAlly && this.awareness >= map.param.awareness_canProposeLightAlliance) { issue = new VoteIssue_LightAlliance(society, null, this); VoteOption option_0 = new VoteOption(); option_0.group = null; issue.options.Add(option_0); foreach (SocialGroup sg in society.getNeighbours()) { if (sg is Society == false) { continue; } if (sg == this.society) { continue; } Society other = (Society)sg; if (other.isDarkEmpire) { continue; } VoteOption option_1 = new VoteOption(); option_1.group = sg; issue.options.Add(option_1); //if (lastProposedIssue != null && lastProposedIssue.GetType() == issue.GetType()) { break; }//Already seen this proposal, most likely. Make another or skip //Random factor to prevent them all rushing a singular voting choice double localU = issue.computeUtility(this, option_1, new List <ReasonMsg>()) * Eleven.random.NextDouble(); if (localU > bestU) { bestU = localU; bestIssue = issue; } logVote(issue); } } //Check if you want to execute someone if (society.posture == Society.militaryPosture.introverted) { foreach (Person p in society.people) { if (p == this) { continue; } issue = new VoteIssue_JudgeSuspect(society, p, this); VoteOption option_0 = new VoteOption(); option_0.index = 0; issue.options.Add(option_0); VoteOption option_1 = new VoteOption(); option_1.index = 1; issue.options.Add(option_1); //if (lastProposedIssue != null && lastProposedIssue.GetType() == issue.GetType()) { break; }//Already seen this proposal, most likely. Make another or skip //Random factor to prevent them all rushing a singular voting choice double localU = issue.computeUtility(this, option_1, new List <ReasonMsg>()) * Eleven.random.NextDouble(); if (localU > bestU) { bestU = localU; bestIssue = issue; } logVote(issue); } } foreach (Unit u in map.units) { if (u.person == null) { continue; } if (getRelation(u.person).getLiking() >= 0) { continue; } if (society.enemies.Contains(unit)) { continue; } issue = new VoteIssue_CondemnAgent(society, u, this); VoteOption option_0 = new VoteOption(); option_0.index = 0; issue.options.Add(option_0); VoteOption option_1 = new VoteOption(); option_1.index = 1; issue.options.Add(option_1); //if (lastProposedIssue != null && lastProposedIssue.GetType() == issue.GetType()) { break; }//Already seen this proposal, most likely. Make another or skip //Random factor to prevent them all rushing a singular voting choice double localU = issue.computeUtility(this, option_1, new List <ReasonMsg>()) * Eleven.random.NextDouble(); if (localU > bestU) { bestU = localU; bestIssue = issue; } logVote(issue); } } } if (bestIssue != null) { if (World.logging) { log.takeLine("CHOSE: " + bestIssue.ToString()); } } //lastProposedIssue = bestIssue; return(bestIssue); }