The years go by - is any idea for a community Civ3-clone utterly dead? :)

That's a very informative post, Civinator. I'd heard of the ToT Patch Project in passing, but had no idea it encompassed so much. That sounds like a lot of what we want in Civ3.

Meanwhile I have downloaded that patch. In the readme there are some other interesting features that could be useful for such a project in C3C, too:

- Defense bonus: Configure multiple defensive bonuses.
- Movement multipliers: Configure movement cost along roads, railroads and rivers.
- Navigable rivers: Allows ships to sail on rivers.
- Landmarks: Allows custom text to be added to map tiles.
- City and unit limits: New, configurable limits up to 32,000.
 
Who me? I've been talking with Quintillus about technical challenges. There are still a few unresolved issues with implementing the world map in Unity. I'm going to take a closer look at Godot, a fully open source game engine that also supports C# and other languages for scripting. The first milestone is to demonstrate the architecture by making an end-to-end executable "game" with mod/config files, art assets, game library, engine, and UI featuring a scrolling, wrapped map, which can be distributed and installed. It won't look like much at that point but most of the hard questions will be answered.
 
I know I'm barely active and I'm a lowly novice. So I will just pop in one thing then run off into the darkness and leave you guys alone. :)

One thing that held me back so much on Civ3 modding was the difficulty of adding an unit, a resource, or a building. Toying with stats and other things... on the other hand, incredibly easy enough for a rookie like me.
 
I know I'm barely active and I'm a lowly novice. So I will just pop in one thing then run off into the darkness and leave you guys alone. :)

One thing that held me back so much on Civ3 modding was the difficulty of adding an unit, a resource, or a building. Toying with stats and other things... on the other hand, incredibly easy enough for a rookie like me.

Don't be so modest, most of us are thrilled to have more participation, especially from infrequent posters. Although it's probably more so for me, as you're the first other person I've seen in the Civ3 forums from C-Bus (though we do have someone from Cincy, used to have someone from Delaware, and have someone with ties to Athens).

I agree, though, there are a lot of boxes to check for adding new content for scenarios. And while the CFC Download Database helps a lot, being able to download units others have created and not having to create everything from scratch, there are still quite a few boxes to check off. PCXs, entries in BIQs, Civilopedia entries, sometimes additional text file entries... and you don't necessarily get much help at knowing what, if anything, you missed.

That was the main inspiration for one of the components of my editor that I fear is in a bit of a chicken-and-egg problem. Namely, the "Download Units" option I have on my editor tab (description in help file here). Admittedly, it needs a bit of polish for ease of use, which I've procrastinated on due to a lack of people expressing interest in it. But the idea is if you are editing a scenario, wouldn't it be nice to say you want to add a unit, go to CFC and download the one you want, have the files automatically put in the right place within your scenario's files, and have it also be added to your BIQ with the name of your choosing, including automatic renaming of the downloaded files? That's what it currently does (in general; there are a few edge cases that cause it to fail), and it could be extended to, for example, letting you automatically add a Civilopedia entry (either adding the content there, or just a placeholder), or downloading other things such as buildings or leaderheads. The main reasons I haven't extended it are lack of interest from the editor's users, and that I don't actually create scenarios a whole lot myself. Although I still think that if I'd made that available a few years earlier and had extended it, it might have seen decent uptake due to making the adding-new-units-and-so-forth process significantly easier.

I should also note that the later games don't make this any better, and make it more difficult to toy with the stats. But that doesn't mean there isn't room for improvement in Civ3.
 
In my eyes it would be a big step forward, if a lua scripting could be added to C3C as it was possible for Civ 2 with Civ 2 TOTPP: https://forums.civfanatics.com/threads/totpp-lua-function-reference.557527/

The future of Civ 2 ToT becomes more and more exciting! :woohoo:

I would be curious as to the technical aspect of how that works, or more accurately a summary of it. Is it similar to the patches Antal1987 wrote for Civ3, only developed to a further degree and thus now offering a greater degree of possibilities, or a different approach?

In other news, I miss the ability to download 45-page threads all at once so I can search them more easily, and also need more hours in the day.
 
Hi Quintillus, I´m no programmer, but my guess is, the approach of Antal1987 and of TNO are different. I have the feeling, Antal1987 achieved his solutions by starting with hexediting, while TNO did really programming. Additionally it seems, TNO added own code to Civ 2 ToT, to allow the blinking of units and to add more functions (like navigable rivers) and more memory to the game.

At present some modders try to do their first mods using lua instead of the old Civ 2 ToT events. An interesting question for me -as a non-programmer- could be, where to position such a lua coding in the structure of civ 3. There are some 'event-like' features in C3C (autoproduction, volcanos, plague). May be this is the port for introducing lua to C3C?

This is the introduction to lua scripting attached to the TOTPP download:

Spoiler :
With Lua scripting, scenario designers can finally replace the Test of Time macro language with a full-scale language. Of course, this offers endless new possibilities previously unthought of, but the first thing many designers would like to do is to migrate their familiar events to the unfamiliar Lua scripting language and the `civ` library (the library containing the bindings to interact with the game). This document describes replacement functionality for the macro language in Lua.
========
Triggers
========
AlphaCentauriArrival
--------------------
Use `civ.scen.onCentauriArrival`. The callback receives the arriving tribe as parameter. For replacement of the `size` parameter, use the components of `tribe.spaceship`.
@IF
AlphaCentauriArrival
race=anybody
size=3
@THEN
...
civ.scen.onCentauriArrival(function (tribe)
if tribe.spaceship.habitation >= 3 and tribe.spaceship.lifesupport >= 3 then
...
end
end)
BribeUnit
---------
Use `civ.scen.onBribeUnit`. The callback receives the unit and the previous owner as parameters (`unit.owner` points to the bribing tribe).
@IF
BRIBEUNIT
who=ANYBODY
whom=BARBARIANS
unittype=56
@THEN
...
civ.scen.onBribeUnit(function (unit, previousOwner)
if unit.type.id == 56 and previousOwner.id == 0 then
...
end
end)
CheckFlag
---------
Replaced by operators and variables.
CityDestroyed
-------------
Use `civ.scen.onCityDestroyed`. The callback receives the city that is destroyed.
@IF
CITYDESTROYED
city=Rot
owner=Barbarians
@THEN
...
civ.scen.onCityDestroyed(function (city)
if city.name == "Rot" and city.owner.name == "Barbarians" then
...
end
end)
CityProduction
--------------
Use `civ.scen.onCityProduction`. The callback receives the city and the produced item (unit, improvement or wonder) as parameters. Use one of the civ.isX functions to test the type of the produced item. Test `city.owner` as the replacement for `builder`.
@IF
CITYPRODUCTION
builder=anybody
unit=Shuttle
@THEN
...
civ.scen.onCityProduction(function (city, prod)
if civ.isUnit(prod) and prod.type.name == "Shuttle" then
...
end
end)
CityTaken
---------
Use `civ.scen.onCityTaken`. The callback receives the city and the defending tribe as parameters (`city.owner` refers to the attacking tribe, the trigger runs after capture).
@IF
CITYTAKEN
city=Oldgrange
attacker=ANYBODY
defender=Humans
@THEN
...
civ.scen.onCityTaken(function (city, defender)
if city.name == "Oldgrange" and defender.name == "Humans" then
...
end
end)
Negotiation
-----------
Replaced by `civ.scen.onNegotiation`. The callback receives the talking and listening tribes. Return `true` to allow negotiation, `false` to disallow. This can completely replace complex talker/listenermasks and the Negotiator action with just a few lines:
@IF
Negotiation
talkermask=0b00000000000101010110101011010101
listenermask=0b00000000000010101001010100101010
@THEN
@ENDIF
@IF
Negotiation
talkermask=0b00000000000010101001010100101010
listenermask=0b00000000000101010110101011010101
@THEN
@ENDIF
@IF
ReceivedTechnology
Receiver=Anybody
Technology=14
@THEN
Negotiator
who=triggerreceiver
type=talker
state=clear
@ENDIF
@IF
ReceivedTechnology
Receiver=Anybody
Technology=14
@THEN
Negotiator
who=triggerreceiver
type=listener
state=clear
@ENDIF
local isAlien = function (tribe) return tribe.id % 2 == 0 end
civ.scen.onNegotiation(function (talker, listener)
local xeno = civ.getTech(14)
return isAlien(talker) == isAlien(listener) or
talker:hasTech(xeno) or listener:hasTech(xeno)
end)
NoSchism
--------
Use `civ.scen.onSchism`. The callback receives the tribe that is about to split up. Return `true` to allow the schism, `false` to disallow.
@IF
NOSCHISM
DEFENDER=anybody
@THEN
@ENDIF
civ.scen.onSchism(function (tribe)
return false
end)
RandomTurn
----------
Use `civ.scen.onTurn` in combination with math.random.
@IF
RANDOMTURN
denominator=20
@THEN
...
civ.scen.onTurn(function (turn)
if math.random(1, 20) == 20 then
...
end
end)
ReceivedTechnology
------------------
Normally, you'd use the `civ.scen.onTurn` callback in combination with one of the following tests. For receiver=anybody, use the `researched` property of a tech. For a specific receiver, use `tribe:hasTech(tech)`. For the number of future techs, use tribe.futureTechs.
@IF
RECEIVEDTECHNOLOGY
receiver=Humans
technology=38
@And
RECEIVEDTECHNOLOGY
receiver=Anybody
technology=44
@THEN
...
civ.scen.onTurn(function (turn)
local humanTribe = civ.getTribe(2)
if humanTribe:hasTech(civ.getTech(38)) and civ.getTech(44).researched then
...
end
end
ScenarioLoaded
--------------
Use `civ.scen.onScenarioLoaded`. The callback takes no parameters. Useful for restoring state after loading.
@IF
SCENARIOLOADED
@THEN
...
civ.scen.onScenarioLoaded(function ()
...
end)
Turn
----
Use `civ.scen.onTurn`. The callback receives the turn as parameter.
@IF
TURN
turn=10
@THEN
...
civ.scen.onTurn(function (turn)
if turn == 10 then
...
end
end)
TurnInterval
------------
Use `civ.scen.onTurn` in combination with the modulo operator.
@IF
TURNINTERVAL
interval=4
@THEN
...
civ.scen.onTurn(function (turn)
if turn % 4 == 0 then
...
end
end)
UnitKilled
----------
Use `civ.scen.onUnitKilled`. The callback receives the defending and attacking units as parameters.
@IF
UNITKILLED
map=0
unit=Warriors
attacker=Anybody
defender=Barbarians
@THEN
...
civ.scen.onUnitKilled(function (defender, attacker)
if defender.type.name == "Warriors" and
defender.z == 0 and
defender.owner.name == "Barbarians" then
...
end
end)
=======
Actions
=======
BestowImprovement
-----------------
For improvements, call `city:AddImprovement(improvement)` or `city:RemoveImprovement(improvement)`. For wonders, set `wonder.city`:
local city = civ.getCurrentTile().city
local granary = civ.getImprovement(3)
local wonder = civ.getWonder(1)
city:AddImprovement(granary)
wonder.city = city
city:RemoveImprovement(granary)
wonder.city = nil
ChangeMoney
-----------
Set the `money` property of a tribe, e.g.:
tribe = civ.getTribe(1)
tribe.money = tribe.money + 1000
ChangeTerrain
-------------
Set the `terrainType` property of a tile to the index of the desired terrain type, e.g.:
tile = civ.getCurrentTile()
tile.terrainType = 1
CreateUnit
----------
You can either use the low-level `civ.createUnit(unittype, tribe, tile)`, which will just create the unit, but does no checks to see if the unit is actually allowed on the specified tile, or alternatively you can use `civlua.createUnit(unittype, tribe, locations, options)`, which implements all the options and checks of the original CreateUnit action:
unit = civ.createUnit(civ.getUnitType(2), civ.getCurrentTribe(), civ.getCurrentTile())
civlua = require("civlua")
units = civlua.createUnit(civ.getUnitType(2), civ.getCurrentTribe(), {{0, 0, 0}, {1, 1, 0}, {2, 2, 0}}, {count=3, randomize=true, veteran=true})
DestroyACivilization
--------------------
Use `tribe:kill()`:
civ.getTribe(0):kill()
EnableTechnology
----------------
Use `tribe:enableTechGroup(techGroup, value)`, which takes a tech group (0-7) (see @LEADERS2) and a tech code (0-2) (0 = can research, can own, 1 = can't research, can own, 2 = can't research, can't own):
civ.getCurrentTribe():enableTechGroup(civ.getTech(99).group, 0)
EndGame
-------
Call `civ.endGame(endscreens)`. The endscreens parameter (`true` or `false`) is the same as in the EndGame action.
EndGameOverride
---------------
Use the `civ.scen.onGameEnds` event. The callback receives the reason the game is ending (space ship arrives (1 and 2), conquest (3), game over (4), retiring (5), from a call to civ.endGame (6)). Return true to end the game, false to keep playing:
civ.scen.onGameEnds(function (reason)
return reason ~= 5 or civ.getGameYear() > 2100
end)
Flag
----
Flags are replaced by variables. For continuous flags, make sure you persist them in your local state table.
GiveTechnology
--------------
Use `tribe:giveTech(tech)`. To set the number of future technologies the tribe has researched, set `tribe.futureTechs`:
tribe = civ.getCurrentTribe()
tribe:giveTech(civ.getTech(21))
tribe.futureTechs = 3
MakeAggression
--------------
Use either `civ.makeAggression`, which does exactly the same as the original action. Or set `tribe.treaties[anotherTribe]` for low-level control over treaties. For example, you can make peace with the Barbarians:
civ.getCurrentTribe().treaties[civ.getTribe(0)] = 0x405
ModifyReputation
----------------
Set `tribe.reputation[otherTribe]`, `tribe.attitude[otherTribe]` or `tribe.betrayals`.
MoveUnit
--------
Set `unit.gotoTile` to make the unit move to the specified tile programatically, which does pretty much the same thing as the MoveUnit action. Or use `civ.teleportUnit(unit, tile)`, a low-level function to put the unit on the tile without any cost to movement points or regard for location.
civ.getActiveUnit().gotoTile = civ.getTile(0, 0, 0)
civ.teleportUnit(civ.getCurrentTile().units(), civ.getTile(0, 0, 0))
Negotiator
----------
Unnecessary, since there are no negotiation flags anymore. The return value of the `onNegotiation` callback determines if negotiation is allowed or not.
PlayAviFile
-----------
Use `civ.playVideo(filename)`.
PlayCDTrack
-----------
Use `civ.playCDTrack(trackID)`, or with the DirectShow Music patch enabled, also `civ.playCDTrack(filename)`, where filename is relative to the `Music` directory.
PlayWaveFile
------------
Use `civ.playSound(filename)`.
TakeTechnology
--------------
Use `tribe:takeTech(tech, collapse=false)`. The first parameter is the technology to take away, the optional `collapse` parameter determines whether to take away all techs that have `tech` as a prerequisite somewhere up the tree.
Text
----
Use `civ.ui.text(text)`. For an equivalent to 'No Broadcast', check if the triggering tribe is a human player.
if tribe.isHuman then
civ.ui.text("Some text")
end
Transport
---------
Set `unittype.nativeTransport`, `unittype.buildTransport` or `unittype.useTransport`. These are the masks as in columns D-F in @UNITS_ADVANCED. To allow engineers to build transport relationship 10:
local engineer = civ.getUnitType(1)
engineer.buildTransport = engineer.buildTransport | (1 << 10)
=========
Modifiers
=========
Continuous
----------
Not really necessary as such. To persist values put them in a state table, and make sure that this table is serialized.
Delay
-----
To delay actions, just write it yourself, as long as you make sure the counter is serialized:
civ.scen.onTurn(function (turn)
if state.delay > 0 then
state.delay = state.delay - 1
end
if state.delay == 0 then
doSomeAction()
end
end)
JustOnce
--------
Use civlua.justOnce or implement it yourself. civlua.justOnce takes a property holding a boolean and a callback as parameters:
civlua.justOnce(civlua.property(someTable, "key"), function ()
...actions...
end)
justOnce invokes .get() on the property, when this returns false, it runs the callback and invokes .set(true) on the property. When .get() returns true, does nothing. For example:
local state = {someEventHappened = false}
local justOnce = function (key, f) civlua.justOnce(civlua.property(state, key), f) end
...
if someEvent then
justOnce("someEventHappened", function ()
doSomeAction()
end)
end
Now, if someEvent occurs, the key `someEventHappened` is checked in `state`. If this is still false, it runs the callback, which runs `doSomeAction`. After this, `state.someEventHappened` will be true, so it won't be run again.
Randomize
---------
Used as an option to randomize locations in civlua.createUnit. Use math.random for other situations.
 
Last edited:
Very interesting! :) To still have isometric view in my eyes is a very good decision.
WildWeazel spoke about Unity some posts above.
 
Thanks @register that looks like a great series and just the kind of thing I was looking for. I'm interested to see his solutions for the map features. I've had an intense few weeks at work, first a whirlwind recruiting trip to Florida and then a long weekend tiger team effort, so I've had no time yet to try out Godot. Has anyone here used it?
 
Interesting, Civinator... it seems there is indeed a way it interacts with the game, but I don't know what that might be. That Civ2 already had a scripting language may have helped with making it extensible. I would not know where to start in terms of trying to add Lua (or any other language) scripting to Civ3.

Good finds, register. But it's a coincidence! It's certainly an interesting idea though, live stream game-making tutorials. And it's great that, like WildWeazel, he's looking at Unity in particular.
 
Thanks @register that looks like a great series and just the kind of thing I was looking for. I'm interested to see his solutions for the map features. I've had an intense few weeks at work, first a whirlwind recruiting trip to Florida and then a long weekend tiger team effort, so I've had no time yet to try out Godot. Has anyone here used it?

Civers who want to know more about Godot can read more about it here:

https://en.wikipedia.org/wiki/Godot_(game_engine)
http://www.gamefromscratch.com/page/Godot-Game-Engine-tutorial-series.aspx

Interesting, Civinator... it seems there is indeed a way it interacts with the game, but I don't know what that might be. That Civ2 already had a scripting language may have helped with making it extensible. I would not know where to start in terms of trying to add Lua (or any other language) scripting to Civ3.

That´s a pitty, but we are only normal human beeings.:think:
 
Well, yes. Most of the community here are in their 30s or over, with jobs that take most of their time, so it is difficult to find anyone...

Eventually some of us will start retiring?

Interesting conversation and early efforts. I can't even commit to reliable moral support time, but it's an interesting set of problems to think about.
 
As I alluded to before, I've been [taking my sweet time] looking closer into Godot as an alternative engine to Unity. The recent 3.0 release of Godot introduces major new relevant features including C# 7.0 and other scripting language support, improved tilemaps, a network multiplayer API, and tons more (new and improved 3D renderer and asset management being the headliners). After trying it out and reading up on it, I would suggest that for a new user, Godot would be the preferred engine for this type of game. Compared to Unity it is more geared towards 2D games, has stronger native support for tilemap worlds, is a leaner and simpler platform to learn, and is fully open-source and cross-platform.

However, that is not enough to outweigh the familiarity factor for me personally. I already know the essentials of Unity and will continue to learn and work with it for the foreseeable future. Instead of picking up another similar tool in parallel, I'd rather build experience with Unity even if it isn't the ideal tool for the job. And hey, going by my original plan, it's a decoupled open source project. If you don't like it you can take the game library and slap another GUI on it.
 
As I alluded to before, I've been [taking my sweet time] looking closer into Godot as an alternative engine to Unity. The recent 3.0 release of Godot introduces major new relevant features including C# 7.0 and other scripting language support, improved tilemaps, a network multiplayer API, and tons more (new and improved 3D renderer and asset management being the headliners). After trying it out and reading up on it, I would suggest that for a new user, Godot would be the preferred engine for this type of game. Compared to Unity it is more geared towards 2D games, has stronger native support for tilemap worlds, is a leaner and simpler platform to learn, and is fully open-source and cross-platform.

However, that is not enough to outweigh the familiarity factor for me personally. I already know the essentials of Unity and will continue to learn and work with it for the foreseeable future. Instead of picking up another similar tool in parallel, I'd rather build experience with Unity even if it isn't the ideal tool for the job. And hey, going by my original plan, it's a decoupled open source project. If you don't like it you can take the game library and slap another GUI on it.

When will it be operational, corporal WildWeazel, sir? ^^
 
Last edited:
As a former coworker would say when asked for any estimate, "six months and two million dollars."

Before formally committing to anything I want to go back to Unity and "finish" my proof-of-concept with the full stack of communication: config file -> game library -> Unity -> map window, with a preliminary solution for scrolling and wrapping, and a "unit" that navigates tiles turn by turn.

corporal WildWeazel, sir? ^^
Don't call me 'sir', I work for a living! :salute:
 
Back
Top Bottom