Skip to content

Commit

Permalink
Award techs to the player when fully researched
Browse files Browse the repository at this point in the history
... and show progress in the UI.

#392
  • Loading branch information
TomWerner committed Jan 27, 2025
1 parent 6b64674 commit c0927c5
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 4 deletions.
17 changes: 14 additions & 3 deletions C7/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,14 @@ public void processEngineMessages(GameData gameData) {
// F6 is the science advisor.
// TODO: Move the F* key strings to a set of constants/enum.
EmitSignal(SignalName.ShowSpecificAdvisor, "F6");
Tech tech = gameData.techs.Find(x => x.id == gameData.GetHumanPlayers()[0].currentlyResearchedTech);
Player player = gameData.GetHumanPlayers()[0];
Tech tech = gameData.techs.Find(x => x.id == player.currentlyResearchedTech);

// TODO: calculate research speed.
EmitSignal(SignalName.UpdateTechProgress, tech.Name, -1);
if (tech != null) {
EmitSignal(SignalName.UpdateTechProgress, tech.Name, player.EstimateTurnsToResearch(tech));
} else {
EmitSignal(SignalName.UpdateTechProgress, "Not selected", (int)1e9);
}
break;
case MsgUpdateUiAfterSliderChange mUUASC:
// F1 is the science advisor.
Expand Down Expand Up @@ -348,6 +352,13 @@ private void OnPlayerStartTurn() {
Player player = gameDataAccess.gameData.GetHumanPlayers()[0];

EmitSignal(SignalName.TurnStarted, turnNumber, player.gold, /*goldPerTurn=*/0);

Tech tech = gameDataAccess.gameData.techs.Find(x => x.id == player.currentlyResearchedTech);
if (tech != null) {
EmitSignal(SignalName.UpdateTechProgress, tech.Name, player.EstimateTurnsToResearch(tech));
} else {
EmitSignal(SignalName.UpdateTechProgress, "Not selected", (int)1e9);
}
CurrentState = GameState.PlayerTurn;

GetNextAutoselectedUnit(gameDataAccess.gameData);
Expand Down
2 changes: 1 addition & 1 deletion C7/UIElements/GameStatus/LowerRightInfoBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public void SetTurnAndGold(int turnNumber, int gold, int goldPerTurn) {
}

public void UpdateTechProgress(string techName, int turnsRemaining) {
if (turnsRemaining > 0) {
if (turnsRemaining >= 1e9) {
SetTextAndCenterLabel(scienceProgress, $"{techName} (-- turns)");
} else {
SetTextAndCenterLabel(scienceProgress, $"{techName} ({turnsRemaining} turns)");
Expand Down
10 changes: 10 additions & 0 deletions C7Engine/EntryPoints/TurnHandling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ internal static void AdvanceTurn() {
gameData.turn++;
foreach (Player player in gameData.players) {
player.turnsResearched++;

// Check to see if the player has finished researching their
// tech, and if they have, add it to the list of known techs
if (player.currentlyResearchedTech != null) {
Tech tech = gameData.techs.Find(x => x.id == player.currentlyResearchedTech);
if (player.EstimateTurnsToResearch(tech) <= 0) {
player.knownTechs.Add(player.currentlyResearchedTech);
player.SetCurrentlyResearchedTech(null);
}
}
}
OnBeginTurn();
}
Expand Down
45 changes: 45 additions & 0 deletions C7GameData/Player.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using C7Engine.AI.StrategicAI;
Expand Down Expand Up @@ -117,6 +118,50 @@ public override string ToString() {
return civilization.cityNames.First();
return "";
}

public int EstimateTurnsToResearch(Tech tech) {
// Cost formula from https://forums.civfanatics.com/threads/research-cost-formula-v1-29f.29485/.
// Research Cost = [MM * [10*COST * (1 - N/[CL*1.75])]/(CF * 10)] - progress
//
// MM = map modifier (tiny=160, small=200, standard=240, large=320, huge=400)
// COST = tech cost
// CF = difficulty factor, range 10 (easy) to 6 (hard)
// N = number of known civs that have discovered the tech
// CL = civs left in game
//
// We also have the min/max turns to research of 4 and 50.
// TODO: the min/max costs are in the biq, we should load them.
// TODO: implement the civ-related parts of the equation
// TODO: figure out what map size we are
// TODO: See this this whole equation can be configurable
int beakersPerTurn = 0;
foreach (City city in cities) {
beakersPerTurn += (int)Math.Floor(city.CurrentCommerceYield() * city.owner.scienceRate / 10.0);
}

if (beakersPerTurn == 0) {
// No research is happening.
Console.WriteLine("no research");
return (int)1e9;
}

int mapModifier = 160; // small, to make testing faster
int difficultyFactor = 10; // easy difficulty
int researchCost = mapModifier * 10 * tech.Cost / (difficultyFactor * 10);
int remainingCost = researchCost - beakers;
int turnsRemaining = (int)Math.Ceiling((double)remainingCost / beakersPerTurn);

// We never spend more than 50 turns per tech.
int maxTurnsRemaining = 50 - turnsResearched;

int result = Math.Min(turnsRemaining, maxTurnsRemaining);

// Ensure every tech takes at least 4 turns.
if (result < 4 && turnsResearched < 4) {
return 4;
}
return result;
}
}

}

0 comments on commit c0927c5

Please sign in to comment.