Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions C7/Lua/rules/civ3.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ return {
--]]
terraforms = require "civ3.terraforms",
terrain_improvements = require "civ3.terrain_improvements",
inflows = require "civ3.inflows"
}
81 changes: 81 additions & 0 deletions C7/Lua/rules/civ3/inflows.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
local function rules()
return GAME_DATA().rules
end

local inflows = {}

-- to match an item in a list based on a predicate
local function any(list, predicate)
for _, v in ipairs(list) do
if predicate(v) then
return true
end
end
return false
end

-- context is [ int input, List<Tech> techs ]
-- this is the actual implementation we would do for Wealth, for conquests
local function extra_commerce_calculation(context)
local useful_shields = context.input
local known_techs = context.techs
local double_effect = any(known_techs,
function(x)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this lambda be pulled out to a named function? The formatting here otherwise makes this a little weird to read

return x.DoublesWealthProduction == true
end
)
local ratio = rules().ShieldCostPerGold
return math.max(1, useful_shields / (double_effect and (ratio / 2) or ratio))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the lua nits, feel free to ignore this

But would doing local ratio = double_effect and (rules().ShieldCostPerGold / 2) or rules().ShieldCostPerGold make sense?

end

-- example
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this and the one below, what would this be an example of? Could you document the idea in the code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made this look more like it should now, and added a comment to document the usage of this. let me know if it's enough, or I should add more.

Since it makes sense to me as I wrote it, I might be missing the bigger picture.

local function extra_culture_calculation(context)
local city_culture = context.input
return math.max(1, city_culture/2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these default to doing nothing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it was there purely as an example instead of trying to explain it with words

end

-- example
local function extra_science_calculation(context)
local beakers = context.input
return math.max(0, beakers/10)
end

inflows.result = {
wealth = {
commerce = function(context)
return extra_commerce_calculation(context)
end,
culture = function(context)
return extra_culture_calculation(context)
end,
science = function(context)
return extra_science_calculation(context)
end,
},
-- example
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto with these examples - I know the PR has some details, but if we document here too it avoids having to go through git blame

cultivation = {
commerce = function(context)
return extra_commerce_calculation(context) * 2
end,
culture = function(context)
return extra_culture_calculation(context) * 2
end,
science = function(context)
return extra_science_calculation(context) * 2
end,
},
-- example
expertise = {
commerce = function(context)
return extra_commerce_calculation(context) * 3
end,
culture = function(context)
return extra_culture_calculation(context) * 3
end,
science = function(context)
return extra_science_calculation(context) * 3
end,
},
}

return inflows
10 changes: 5 additions & 5 deletions C7/Lua/texture_configs/civ3/building_icons.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ local building_icons = {
}

function building_icons.small:map_object_to_sprite(building)
if (building:GetType().Name ~= "Building") then
error "Expected a Building object"
if (building:GetType().Name ~= "Building" and building.GetType().Name ~= "Inflow") then
error("Expected a Building or a Inflow object, got " .. type(building:GetType().Name))
end

local y = 1 + 33 * (1 + building.iconRowIndex)
local y = 33 + (SMALL_ICON_HEIGHT + 1) * building.iconRowIndex

return {
path = self.extra_data.path,
Expand All @@ -30,8 +30,8 @@ function building_icons.small:map_object_to_sprite(building)
end

function building_icons.large:map_object_to_sprite(building)
if (building:GetType().Name ~= "Building") then
error "Expected a Building object"
if (building:GetType().Name ~= "Building" and building.GetType().Name ~= "Inflow") then
error("Expected a Building or a Inflow object, got " .. type(building:GetType().Name))
end

local y = 33 + (LARGE_ICON_HEIGHT + 1) * building.iconRowIndex
Expand Down
64 changes: 62 additions & 2 deletions C7/Text/c7-static-map-save-standalone.json
Original file line number Diff line number Diff line change
Expand Up @@ -71317,6 +71317,62 @@
]
}
],
"inflows": [
{
"name": "Wealth",
"iconRowIndex": 29,
"localYield": [
{
"yieldType": "commerce",
"yieldCalculation": "inflows.result.wealth.commerce"
},
{
"yieldType": "culture",
"yieldCalculation": "inflows.result.wealth.culture"
},
{
"yieldType": "science",
"yieldCalculation": "inflows.result.wealth.science"
}
]
},
{
"name": "Cultivation",
"iconRowIndex": 29,
"localYield": [
{
"yieldType": "commerce",
"yieldCalculation": "inflows.result.cultivation.commerce"
},
{
"yieldType": "culture",
"yieldCalculation": "inflows.result.cultivation.culture"
},
{
"yieldType": "science",
"yieldCalculation": "inflows.result.cultivation.science"
}
]
},
{
"name": "Expertise",
"iconRowIndex": 29,
"localYield": [
{
"yieldType": "commerce",
"yieldCalculation": "inflows.result.expertise.commerce"
},
{
"yieldType": "culture",
"yieldCalculation": "inflows.result.expertise.culture"
},
{
"yieldType": "science",
"yieldCalculation": "inflows.result.expertise.science"
}
]
}
],
"players": [
{
"id": "player-1",
Expand Down Expand Up @@ -73497,9 +73553,10 @@
"scoutUnitType": "Scout",
"maxRankOfWorkableTiles": 2,
"maxRankOfBarbarianCampTiles": 2,
"defaultDealDuration": 20,
"defaultDealDuration": 20,
"treasuryInterestRate": 0.05,
"maxInterest": 50
"maxInterest": 50,
"shieldCostPerGold": 4
},
"techs": [
{
Expand Down Expand Up @@ -73989,6 +74046,9 @@
"y": 276,
"prerequisites": [
"tech-32"
],
"flags": [
"doublesWealthProduction"
]
},
{
Expand Down
64 changes: 62 additions & 2 deletions C7/Text/c7-static-map-save.json
Original file line number Diff line number Diff line change
Expand Up @@ -73890,6 +73890,62 @@
]
}
],
"inflows": [
{
"name": "Wealth",
"iconRowIndex": 29,
"localYield": [
{
"yieldType": "commerce",
"yieldCalculation": "inflows.result.wealth.commerce"
},
{
"yieldType": "culture",
"yieldCalculation": "inflows.result.wealth.culture"
},
{
"yieldType": "science",
"yieldCalculation": "inflows.result.wealth.science"
}
]
},
{
"name": "Cultivation",
"iconRowIndex": 29,
"localYield": [
{
"yieldType": "commerce",
"yieldCalculation": "inflows.result.cultivation.commerce"
},
{
"yieldType": "culture",
"yieldCalculation": "inflows.result.cultivation.culture"
},
{
"yieldType": "science",
"yieldCalculation": "inflows.result.cultivation.science"
}
]
},
{
"name": "Expertise",
"iconRowIndex": 29,
"localYield": [
{
"yieldType": "commerce",
"yieldCalculation": "inflows.result.expertise.commerce"
},
{
"yieldType": "culture",
"yieldCalculation": "inflows.result.expertise.culture"
},
{
"yieldType": "science",
"yieldCalculation": "inflows.result.expertise.science"
}
]
}
],
"players": [
{
"id": "player-1",
Expand Down Expand Up @@ -76070,9 +76126,10 @@
"scoutUnitType": "Scout",
"maxRankOfWorkableTiles": 2,
"maxRankOfBarbarianCampTiles": 2,
"defaultDealDuration": 20,
"defaultDealDuration": 20,
"treasuryInterestRate": 0.05,
"maxInterest": 50
"maxInterest": 50,
"shieldCostPerGold": 4
},
"techs": [
{
Expand Down Expand Up @@ -76562,6 +76619,9 @@
"y": 276,
"prerequisites": [
"tech-32"
],
"flags": [
"doublesWealthProduction"
]
},
{
Expand Down
16 changes: 13 additions & 3 deletions C7/UIElements/CityScreen/CityScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,8 @@ private void RenderProductionDetails(GameData gameData, City city) {
child.QueueFree();
}

int marginTop = 35;

if (city.itemBeingProduced is UnitPrototype up) {
AnimationManager animationManager = mapView.game.animationController.civ3AnimData.forUnit(up, MapUnit.AnimatedAction.DEFAULT).animationManager;
ShaderMaterial material = TextureLoader.GetShaderMaterialForUnit(city.owner.colorIndex);
Expand All @@ -601,7 +603,7 @@ private void RenderProductionDetails(GameData gameData, City city) {
// Add the base sprite.
Sprite2D baseImageSprite = new();
baseImageSprite.Texture = baseImage;
baseImageSprite.Position = new Vector2(productionButton.TextureNormal.GetWidth() / 2, 35);
baseImageSprite.Position = new Vector2(productionButton.TextureNormal.GetWidth() / 2.0f, marginTop);
productionButton.AddChild(baseImageSprite);

// Add the tint sprite, hooking up the shader.
Expand All @@ -613,7 +615,12 @@ private void RenderProductionDetails(GameData gameData, City city) {
} else if (city.itemBeingProduced is Building b) {
Sprite2D icon = new();
icon.Texture = TextureLoader.Load("building_icons.large", b, useCache: true);
icon.Position = new Vector2(productionButton.TextureNormal.GetWidth() / 2, 35);
icon.Position = new Vector2(productionButton.TextureNormal.GetWidth() / 2.0f, marginTop);
productionButton.AddChild(icon);
} else if (city.itemBeingProduced is Inflow inflow) {
Sprite2D icon = new();
icon.Texture = TextureLoader.Load("building_icons.large", inflow, useCache: true);
icon.Position = new Vector2(productionButton.TextureNormal.GetWidth() / 2.0f, marginTop);
productionButton.AddChild(icon);
}

Expand All @@ -626,6 +633,7 @@ private void RenderProductionDetails(GameData gameData, City city) {
EngineStorage.ReadGameData((GameData gameData) => {
city.SetItemBeingProduced(p);
RenderProductionDetails(gameData, city);
RenderCulture(city);
});
});
}
Expand Down Expand Up @@ -664,11 +672,13 @@ private void RenderShieldBox(int shieldCost, int shieldsInBox) {
child.QueueFree();
}

int itemsPerColumn = (int)Math.Ceiling((float)shieldCost / shieldsInBoxContainer.Columns);
if (itemsPerColumn == 0) return;

int width = (int)shieldsInBoxContainer.GetParent<CenterContainer>().Size.X;
int height = (int)shieldsInBoxContainer.GetParent<CenterContainer>().Size.Y;

shieldsInBoxContainer.Columns = (int)Math.Ceiling(Math.Sqrt(shieldCost));
int itemsPerColumn = (int)Math.Ceiling((float)shieldCost / shieldsInBoxContainer.Columns);
int iconSize = Math.Min(height / itemsPerColumn, width / shieldsInBoxContainer.Columns);

for (int i = 0; i < Math.Min(shieldCost, shieldsInBox); ++i) {
Expand Down
11 changes: 9 additions & 2 deletions C7/UIElements/CityScreen/ProductionMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public override void _Ready() {

// Load the font we'll use.
FontFile font = ResourceLoader.Load<FontFile>("res://Fonts/NotoSans-Regular.ttf", null, ResourceLoader.CacheMode.Ignore);
font.FixedSize = 12;
font.FixedSize = 10;
fontTheme.DefaultFont = font;
}

Expand All @@ -36,6 +36,9 @@ public void AddItems(GameData gameData, City city, Action<IProducible> choosePro
AddChild(tree);
tree.Columns = 2;
tree.Size = new Vector2(203, 360);
tree.SetColumnExpand(0, true);
tree.SetColumnExpand(1, false);
tree.SetColumnCustomMinimumWidth(1, 50);
TradingTree.ConfigureTreeTheme(tree, fontTheme);

TreeItem root = TradingTree.CreateTreeRoot(tree);
Expand All @@ -46,11 +49,15 @@ public void AddItems(GameData gameData, City city, Action<IProducible> choosePro
TreeItem child = tree.CreateItem(root);
string text = $"{option.name}";
if (option is UnitPrototype proto) {
text += $" {proto.attack}.{proto.defense}.{proto.movement}";
string attackDesc = (proto.bombard > 0) ? $"{proto.attack}({proto.bombard})" : proto.attack.ToString();
text += $" {attackDesc}.{proto.defense}.{proto.movement}";
}
child.SetText(0, text);
child.SetText(1, $"{buildTime} turns");
child.SetIcon(0, RightClickChooseProductionMenu.GetProducibleIcon(option));
child.SetCustomMinimumHeight(40);
child.SetAutowrapMode(0, TextServer.AutowrapMode.WordSmart);
tree.SetColumnTitleAlignment(1, HorizontalAlignment.Right);
itemMapping[child] = option;
}

Expand Down
2 changes: 2 additions & 0 deletions C7/UIElements/RightClickMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ public static ImageTexture GetProducibleIcon(IProducible producible) {
return TextureLoader.Load("unit_icons", proto, useCache: true);
} else if (producible is Building b) {
return TextureLoader.Load("building_icons.small", b, useCache: true);
} else if (producible is Inflow inflow) {
return TextureLoader.Load("building_icons.small", inflow, useCache: true);
} else {
return null;
}
Expand Down
Loading