Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion C7/Credits.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public partial class Credits : Node2D {
public override void _Ready() {
log.Information("Now rolling the credits!");
try {
creditsText = System.IO.File.ReadAllText("./Text/credits.txt");
creditsText = System.IO.File.ReadAllText(ProjectSettings.GlobalizePath(@"res://Text/credits.txt"));
} catch (System.Exception ex) {
log.Error(ex, "Failed to read from credits.txt!");
}
Expand Down
17 changes: 16 additions & 1 deletion C7/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ enum GameState {

GameState CurrentState = GameState.PreGame;

// True if the deal screen is open because an AI player is offering something
// to the human player.
private bool waitingForDealScreen = false;

// CurrentlySelectedUnit is a reference directly into the game state so be careful of race conditions. TODO: Consider storing a GUID instead.
public MapUnit CurrentlySelectedUnit = MapUnit.NONE; //The selected unit. May be changed by clicking on a unit or the next unit being auto-selected after orders are given for the current one.
private bool HasCurrentlySelectedUnit() => CurrentlySelectedUnit != MapUnit.NONE;
Expand Down Expand Up @@ -283,6 +287,13 @@ public void processEngineMessagesLocked(GameData gameData) {
}
EmitSignal(SignalName.ShowSpecificAdvisor, "F1");
break;
case MsgShowTradeOffer mSTO:
diplomacy.ShowDealScreenForPlayer(
mSTO.humanPlayer.id, mSTO.aiPlayer.id,
humanGives: mSTO.aiWant,
humanWants: mSTO.aiGive);
waitingForDealScreen = true;
break;
case MsgDisplayHurryProductionPopup mDHPP:
if (mDHPP.details.errorMessage != null) {
popupOverlay.ShowPopup(
Expand Down Expand Up @@ -328,6 +339,11 @@ public void updateAnimations(GameData gameData) {
}

public override void _Process(double delta) {
if (CurrentState == GameState.ComputerTurn && waitingForDealScreen && !diplomacy.Visible) {
waitingForDealScreen = false;
EngineStorage.FinishUiEvent();
}

ProcessActions();
processEngineMessages();

Expand Down Expand Up @@ -881,7 +897,6 @@ private void ProcessAction(string currentAction) {
return;
}


if (currentAction == C7Action.UnitHold) {
new ActionToEngineMsg(() => CurrentlySelectedUnit?.skipTurn()).send();
}
Expand Down
7 changes: 4 additions & 3 deletions C7/TextureLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ public ConfigEntry() {

static TextureLoader() {
lua = new Lua();
lua.DoString($"package.path = './Text/TextureConfigs/?.lua;./Text/TextureConfigs/*/?.lua'");
string textureConfigFolder = ProjectSettings.GlobalizePath(@"res://Text/TextureConfigs");
lua.DoString($"package.path = '{textureConfigFolder}/?.lua;{textureConfigFolder}/*/?.lua'");

civ3TextureConfig = (LuaTable)lua.DoFile("./Text/TextureConfigs/civ3.lua")[0];
c7TextureConfig = (LuaTable)lua.DoFile("./Text/TextureConfigs/c7.lua")[0];
civ3TextureConfig = (LuaTable)lua.DoFile($"{textureConfigFolder}/civ3.lua")[0];
c7TextureConfig = (LuaTable)lua.DoFile($"{textureConfigFolder}/c7.lua")[0];

textureConfig = civ3TextureConfig;
modernGraphics = false;
Expand Down
4 changes: 3 additions & 1 deletion C7/UIElements/Diplomacy/DealScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ public partial class DealScreen : TextureRect {
TradeOffer opponentOffer = new();
TradeOffer humanOffer = new();

public DealScreen(ID humanPlayer, ID opponentPlayer) {
public DealScreen(ID humanPlayer, ID opponentPlayer, TradeOffer humanGives, TradeOffer humanWants) {
this.humanPlayerId = humanPlayer;
this.opponentPlayerId = opponentPlayer;
this.humanOffer = humanGives;
this.opponentOffer = humanWants;
}

public override void _Ready() {
Expand Down
6 changes: 5 additions & 1 deletion C7/UIElements/Diplomacy/Diplomacy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ private void RemoveOtherScreens() {
}

public void ShowDealScreenForPlayer(ID humanPlayer, ID opponentPlayer) {
ShowDealScreenForPlayer(humanPlayer, opponentPlayer, new TradeOffer(), new TradeOffer());
}

public void ShowDealScreenForPlayer(ID humanPlayer, ID opponentPlayer, TradeOffer humanGives, TradeOffer humanWants) {
RemoveOtherScreens();

dealScreen = new DealScreen(humanPlayer, opponentPlayer);
dealScreen = new DealScreen(humanPlayer, opponentPlayer, humanGives, humanWants);
AddChild(dealScreen);
this.Show();
}
Expand Down
41 changes: 29 additions & 12 deletions C7Engine/AI/PlayerAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,11 +316,6 @@ private static void AttemptTrading(Player us) {
continue;
}

// TODO: Implement AI -> Human tech trading
if (them.isHuman) {
continue;
}

// Figure out what techs are available for trading.
List<Tech> techsTheyCanTrade = gD.techs.FindAll(x => {
return them.knownTechs.Contains(x.id) && !us.knownTechs.Contains(x.id);
Expand All @@ -338,18 +333,25 @@ private static void AttemptTrading(Player us) {
continue;
}

// Figure out the value of what we have available to trade.
TradeOffer weGive = new();
Func<int> CalculateWeGiveValue = () => {
return Math.Max(weGive.GoldEquivalentFor(gD, them), weGive.GoldEquivalentFor(gD, us));
};
TradeOffer weWant = new();
Func<int> CalculateWeWantValue = () => {
return Math.Min(weWant.GoldEquivalentFor(gD, them), weWant.GoldEquivalentFor(gD, us));
};

// Figure out the value of what we have available to trade.
weGive.gold = us.gold;
foreach (Tech t in techsWeCanTrade) {
weGive.techs.Add(t);
}
int ourMaxPossibleOffer = weGive.GoldEquivalentFor(gD, them);
int ourMaxPossibleOffer = CalculateWeGiveValue();

// Going from the most to the least valuable valuable techs, see
// if we can afford them. This greedy algorithm should be good
// enough - we don't need perfect binpacking.
TradeOffer weWant = new();
foreach (Tech t in techsTheyCanTrade) {
int cost = gD.TechCostFor(t, us);
if (cost < ourMaxPossibleOffer) {
Expand All @@ -365,33 +367,48 @@ private static void AttemptTrading(Player us) {
// from the opponent. However, we might be overpaying, possibly
// by a significant amount. Keep removing techs from our offer
// as long as it doesn't make our offer worse than theirs.
int theirOfferValue = weWant.GoldEquivalentFor(gD, us);
int theirOfferValue = CalculateWeWantValue();
for (int i = 0; i < weGive.techs.Count;) {
if (weGive.GoldEquivalentFor(gD, them) - gD.TechCostFor(weGive.techs[i], them) >= theirOfferValue) {
if (CalculateWeGiveValue() - gD.TechCostFor(weGive.techs[i], them) >= theirOfferValue) {
weGive.techs.RemoveAt(0);
} else {
++i;
}
}

// Now use any gold to even things out, if possible.
int remainingDelta = Math.Max(0, weGive.GoldEquivalentFor(gD, them) - theirOfferValue);
int remainingDelta = Math.Max(0, CalculateWeGiveValue() - theirOfferValue);
weGive.gold -= Math.Min(remainingDelta, weGive.gold.Value);

// And ensure we minimize the total gold traded, to keep the
// logs cleaner.
int redundantGold = Math.Min(weGive.gold.Value, weWant.gold.Value);
weGive.gold -= redundantGold;
weWant.gold -= redundantGold;
if (weGive.gold == 0) {
weGive.gold = null;
}
if (weWant.gold == 0) {
weWant.gold = null;
}

// Finally if the deal is too mismatched or only contains a swap
// of gold, abandon it. Otherwise we can execute the deal.
if (weGive.GoldEquivalentFor(gD, them) > 1.1 * weWant.GoldEquivalentFor(gD, us)) {
// TODO: Figure out how the real trade factor in the difficulty
// works.
float tradeFactor = them.isHuman ? 1.0f : 1.1f;
if (CalculateWeGiveValue() > tradeFactor * CalculateWeWantValue()) {
continue;
}
if (weGive.techs.Count == 0 && weWant.techs.Count == 0) {
continue;
}

if (them.isHuman) {
new MsgShowTradeOffer(us, them, weWant, weGive).send();
EngineStorage.WaitForUiEvent();
}

us.ExecuteDeal(gD, them, weWant, weGive);
}
}
Expand Down
14 changes: 14 additions & 0 deletions C7Engine/EntryPoints/MessageToUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,18 @@ public MsgShowTemporaryPopup(string message, Tile location) {
this.location = location;
}
}

public class MsgShowTradeOffer : MessageToUI {
public Player aiPlayer;
public Player humanPlayer;
public TradeOffer aiWant;
public TradeOffer aiGive;

public MsgShowTradeOffer(Player aiPlayer, Player humanPlayer, TradeOffer aiWant, TradeOffer aiGive) {
this.aiPlayer = aiPlayer;
this.humanPlayer = humanPlayer;
this.aiWant = aiWant;
this.aiGive = aiGive;
}
}
}