using System; using System.Collections.Generic; using AI; namespace CevoAILib.Diplomacy { interface ITradeItem { int Code { get; } } class ItemOfChoice : ITradeItem { public int Code { get { return Protocol.opChoose; } } public ItemOfChoice() { } public override string ToString() { return "ItemOfChoice"; } } class CopyOfMap : ITradeItem { public int Code { get { return Protocol.opMap; } } public CopyOfMap() { } public override string ToString() { return "CopyOfMap"; } } class CopyOfDossier : ITradeItem { public readonly Nation Nation; public readonly int TurnOfReport; public CopyOfDossier(Nation nation) { this.Nation = nation; this.TurnOfReport = 0; } // turn will be set by server public CopyOfDossier(Nation nation, int turnOfReport) { this.Nation = nation; this.TurnOfReport = turnOfReport; } public int Code { get { return Protocol.opCivilReport + (Nation.ID << 16) + TurnOfReport; } } public override string ToString() { return string.Format("CopyOfDossier {0}", Nation); } } class CopyOfMilitaryReport : ITradeItem { public readonly Nation Nation; public readonly int TurnOfReport; public CopyOfMilitaryReport(Nation nation) { this.Nation = nation; this.TurnOfReport = 0; } // turn will be set by server public CopyOfMilitaryReport(Nation nation, int turnOfReport) { this.Nation = nation; this.TurnOfReport = turnOfReport; } public int Code { get { return Protocol.opMilReport + (Nation.ID << 16) + TurnOfReport; } } public override string ToString() { return string.Format("CopyOfMilitaryReport {0}", Nation); } } class Payment : ITradeItem { public readonly int Amount; public Payment(int amount) { this.Amount = amount; } public int Code { get { return Protocol.opMoney + Amount; } } public override string ToString() { return string.Format("Payment {0}", Amount); } } class TeachAdvance : ITradeItem { public readonly Advance Advance; public TeachAdvance(Advance advance) { this.Advance = advance; } public int Code { get { return Protocol.opTech + (int)Advance; } } public override string ToString() { return string.Format("TeachAdvance {0}", Advance); } } class TeachAllAdvances : ITradeItem { public int Code { get { return Protocol.opAllTech; } } public TeachAllAdvances() { } public override string ToString() { return "TeachAllAdvances"; } } class TeachModel : ITradeItem { public readonly ModelBase Model; readonly int indexInSharedMemory; public TeachModel(Model model) { this.Model = model; indexInSharedMemory = model.IndexInSharedMemory; } public TeachModel(ForeignModel model) { this.Model = model; indexInSharedMemory = model.IndexInNationsSharedMemory; } public int Code { get { return Protocol.opModel + indexInSharedMemory; } } public override string ToString() { return string.Format("TeachModel {0}", Model); } } class TeachAllModels : ITradeItem { public int Code { get { return Protocol.opAllModel; } } public TeachAllModels() { } public override string ToString() { return "TeachAllModels"; } } class ColonyShipPartLot : ITradeItem { public readonly Building PartType; public readonly int Number; public ColonyShipPartLot(Building partType, int number) { this.PartType = partType; this.Number = number; } public int Code { get { return Protocol.opShipParts + (((int)PartType - (int)Building.ColonyShipComponent) << 16) + Number; } } public override string ToString() { return string.Format("{0} x{1}", PartType, Number); } } class ChangeRelation : ITradeItem { public readonly Relation NewRelation; public ChangeRelation(Relation newRelation) { this.NewRelation = newRelation; } public int Code { get { return Protocol.opTreaty + (int)NewRelation - 1; } } public override string ToString() { return string.Format("ChangeRelation {0}", NewRelation); } } interface IStatement { int Command { get; } } class Notice : IStatement { public Notice() { } public int Command { get { return Protocol.scDipNotice; } } public override string ToString() { return "Notice"; } } class AcceptTrade : IStatement { public AcceptTrade() { } public int Command { get { return Protocol.scDipAccept; } } public override string ToString() { return "AcceptTrade"; } } class CancelTreaty : IStatement { public CancelTreaty() { } public int Command { get { return Protocol.scDipCancelTreaty; } } public override string ToString() { return "CancelTreaty"; } } class SuggestTrade : IStatement { public int Command { get { return Protocol.scDipOffer; } } public readonly ITradeItem[] Offers; public readonly ITradeItem[] Wants; public SuggestTrade(ITradeItem[] offers, ITradeItem[] wants) { if (offers == null) this.Offers = new ITradeItem[0]; else this.Offers = offers; if (wants == null) this.Wants = new ITradeItem[0]; else this.Wants = wants; } unsafe public void FillRawStream(int* rawStream) { rawStream[0] = Offers.Length; for (int i = 0; i < Offers.Length; i++) rawStream[2 + i] = Offers[i].Code; rawStream[1] = Wants.Length; for (int i = 0; i < Wants.Length; i++) rawStream[2 + Offers.Length + i] = Wants[i].Code; } public override string ToString() { string offerString = "nothing"; if (Offers.Length > 0) { offerString = Offers[0].ToString(); for (int i = 1; i < Offers.Length; i++) offerString += " + " + Offers[i].ToString(); } string wantString = "nothing"; if (Wants.Length > 0) { wantString = Wants[0].ToString(); for (int i = 1; i < Wants.Length; i++) wantString += " + " + Wants[i].ToString(); } return "SuggestTrade " + offerString + " for " + wantString; } } class SuggestEnd : SuggestTrade { public SuggestEnd() : base(null, null) { } public override string ToString() { return "SuggestEnd"; } } class Break : IStatement { public Break() { } public int Command { get { return Protocol.scDipBreak; } } public override string ToString() { return "Break"; } } static class StatementFactory { static ITradeItem TradeItemFromCode(AEmpire empire, Nation source, int code) { switch (code & Protocol.opMask) { case Protocol.opChoose: return new ItemOfChoice(); case Protocol.opMap: return new CopyOfMap(); case Protocol.opCivilReport: return new CopyOfDossier(new Nation(empire, (code >> 16) & 0xFF), code & 0xFFFF); case Protocol.opMilReport: return new CopyOfMilitaryReport(new Nation(empire, (code >> 16) & 0xFF), code & 0xFFFF); case Protocol.opMoney: return new Payment(code & 0xFFFF); case Protocol.opTech: return new TeachAdvance((Advance)(code & 0xFFFF)); case Protocol.opAllTech: return new TeachAllAdvances(); case Protocol.opAllModel: return new TeachAllModels(); case Protocol.opShipParts: return new ColonyShipPartLot((Building)((int)Building.ColonyShipComponent + (code >> 16) & 0xFF), code & 0xFFFF); case Protocol.opTreaty: return new ChangeRelation((Relation)((code & 0xFFFF) + 1)); case Protocol.opModel: { if (source == empire.Us) return new TeachModel(empire.Models[code & 0xFFFF]); else { foreach (ForeignModel model in empire.ForeignModels) { if (model.Nation == source && model.IndexInNationsSharedMemory == (code & 0xFFFF)) return new TeachModel(model); } } throw new Exception("Error in StatementFactory: Foreign model not found!"); } default: throw new Exception("Error in StatementFactory: Not a valid trade item code!"); } } unsafe public static IStatement OpponentStatementFromCommand(AEmpire empire, Nation opponent, int command, int* rawStream) { switch (command) { case Protocol.scDipNotice: return new Notice(); case Protocol.scDipAccept: return new AcceptTrade(); case Protocol.scDipCancelTreaty: return new CancelTreaty(); case Protocol.scDipOffer: { if (rawStream[0] + rawStream[1] == 0) return new SuggestEnd(); else { ITradeItem[] offers = new ITradeItem[rawStream[0]]; if (rawStream[0] > 0) { for (int i = 0; i < rawStream[0]; i++) offers[i] = TradeItemFromCode(empire, opponent, rawStream[2 + i]); } ITradeItem[] wants = new ITradeItem[rawStream[1]]; if (rawStream[1] > 0) { for (int i = 0; i < rawStream[1]; i++) wants[i] = TradeItemFromCode(empire, empire.Us, rawStream[2 + rawStream[0] + i]); } return new SuggestTrade(offers, wants); } } case Protocol.scDipBreak: return new Break(); default: throw new Exception("Error in StatementFactory: Not a negotiation!"); } } } struct ExchangeOfStatements { public IStatement OurStatement; public IStatement OpponentResponse; public ExchangeOfStatements(IStatement ourStatement, IStatement opponentResponse) { this.OurStatement = ourStatement; this.OpponentResponse = opponentResponse; } } sealed class Negotiation { AEmpire theEmpire; public readonly Phase Situation; public readonly Nation Opponent; public readonly List History = new List(); // sorted from new to old, newest at index 0 IStatement ourNextStatement; public IStatement OurNextStatement { get { return ourNextStatement; } } public Negotiation(AEmpire empire, Phase negotiationSituation, Nation opponent) { this.theEmpire = empire; this.Situation = negotiationSituation; this.Opponent = opponent; } unsafe public PlayResult SetOurNextStatement(IStatement statement) { PlayResult result = PlayResult.Success; if (statement is SuggestTrade) { if (((SuggestTrade)statement).Offers.Length > 2 || ((SuggestTrade)statement).Wants.Length > 2) result = new PlayResult(PlayError.RulesViolation); // check model owners foreach (ITradeItem offer in ((SuggestTrade)statement).Offers) { if (offer is TeachModel && ((TeachModel)offer).Model.Nation != theEmpire.Us) result = new PlayResult(PlayError.RulesViolation); } foreach (ITradeItem want in ((SuggestTrade)statement).Wants) { if (want is TeachModel && ((TeachModel)want).Model.Nation != Opponent) result = new PlayResult(PlayError.RulesViolation); } if (result.OK) { fixed (int* tradeData = new int[14]) { ((SuggestTrade)statement).FillRawStream(tradeData); result = theEmpire.TestPlay(statement.Command, 0, tradeData); } } } else result = theEmpire.TestPlay(statement.Command); if (result.OK) ourNextStatement = statement; return result; } } }