-
Notifications
You must be signed in to change notification settings - Fork 0
javascript Overview
Civilization VII uses JavaScript (compiled from TypeScript) for scripting, replacing Lua from previous Civilization games. Scripts handle map generation, age transitions, UI functionality, and gameplay events.
Located in maps/ directories, these scripts generate terrain, place resources, and set up the map.
Loaded via modinfo:
<MapGenScripts>
<Item>maps/my-map-script.js</Item>
</MapGenScripts>Required Events:
engine.on("RequestMapInitData", requestMapData);
engine.on("GenerateMap", generateMap);Handle game events during age transitions and gameplay scenarios.
Loaded via modinfo:
<ScenarioScripts>
<Item>scripts/my-gameplay-script.js</Item>
</ScenarioScripts>Handle user interface, panels, and visual elements.
Loaded via modinfo:
<UIScripts>
<Item>ui/my-panel.js</Item>
</UIScripts>| Object | Description |
|---|---|
Game |
Current game state, rules, turn info, age |
Players |
Collection of all players |
Units |
Unit management and creation |
Cities |
City management |
Armies |
Army/commander management |
GameInfo |
Database table access |
GameplayMap |
Map data and queries |
GameContext |
Context info (local player, etc.) |
| Object | Description |
|---|---|
TerrainBuilder |
Set terrain, features, elevations |
ResourceBuilder |
Place and manage resources |
MapCities |
City placement on map |
| Object | Description |
|---|---|
Configuration |
Game/map configuration values |
Database |
Direct database operations, hash creation |
| Object | Description |
|---|---|
UI |
UI control and player interface |
Locale |
Localization/text composition |
engine |
Engine event system |
ContextManager |
UI context/screen management |
The engine object handles communication between scripts and the game engine.
// Subscribe to event
engine.on("EventName", callbackFunction);
// With context binding
engine.on("EventName", this.myHandler, this);engine.call("FunctionName", parameters);| Event | Description | Parameters |
|---|---|---|
RequestMapInitData |
Request map initialization data | - |
GenerateMap |
Generate the map | - |
| Event | Description | Parameters |
|---|---|---|
RequestAgeInitializationParameters |
Age transition starting |
initParams (numMajorPlayers, outgoingAge, incomingAge) |
GenerateAgeTransition |
Generate age transition content | - |
| Event | Description | Parameters |
|---|---|---|
GameStarted |
Game has started | - |
TurnBegin |
Turn begins | playerId |
TurnEnd |
Turn ends | playerId |
LocalPlayerTurnBegin |
Local player turn starts | - |
LocalPlayerTurnEnd |
Local player turn ends | - |
| Event | Description | Parameters |
|---|---|---|
UnitAddedToMap |
Unit placed on map | unitId |
UnitRemovedFromMap |
Unit removed from map | unitId |
UnitMoved |
Unit movement complete |
unitId, x, y
|
UnitMovementPointsChanged |
Unit MP changed |
unitId, data
|
UnitPromoted |
Unit gained promotion |
unitId, promotionType
|
| Event | Description | Parameters |
|---|---|---|
CityAddedToMap |
City placed on map | cityId |
CityRemovedFromMap |
City removed | cityId |
CitySelectionChanged |
Selected city changed | cityId |
CityPopulationChanged |
Population changed |
cityId, population
|
CityProductionCompleted |
Production finished |
cityId, productionType
|
| Event | Description | Parameters |
|---|---|---|
DistrictAddedToMap |
District placed | districtInfo |
ConstructibleAddedToMap |
Building/improvement placed | constructibleInfo |
RouteAddedToMap |
Road/route placed | routeInfo |
| Event | Description | Parameters |
|---|---|---|
PlotVisibilityChanged |
Plot visibility updated | plotIndex |
PlotEffectAddedToMap |
Effect added to plot | effectInfo |
PlotEffectRemovedFromMap |
Effect removed | effectInfo |
| Event | Description | Parameters |
|---|---|---|
InputAction |
Input received | actionData |
CameraChanged |
Camera position changed | cameraInfo |
UpdateFrame |
Frame update tick | - |
EndFrame |
Frame ended | - |
UIGameLoadingProgressChanged |
Loading progress | progress |
| Event | Description | Parameters |
|---|---|---|
NetworkDisconnected |
Lost connection | - |
NetworkReconnected |
Connection restored | - |
UserRequestClose |
User requested close | - |
| Event | Description | Parameters |
|---|---|---|
AudioEventReturned |
Audio event completed | tag |
function requestInitializationParameters(initParams) {
console.log("Players:", initParams.numMajorPlayers);
console.log("Old Age:", initParams.outgoingAge);
console.log("New Age:", initParams.incomingAge);
// Modify parameters if needed
engine.call("SetAgeInitializationParameters", initParams);
}
function generateTransition() {
console.log("Generating age transition!");
// Get all players
const players = Players.getEverAlive();
for (const player of players) {
// Process each player's transition
console.log("Processing player:", player.id);
}
}
engine.on("RequestAgeInitializationParameters", requestInitializationParameters);
engine.on("GenerateAgeTransition", generateTransition);The Game object provides access to current game state and rules.
// Current age (as hash)
const currentAge = Game.age;
// Compare ages
if (Game.age == Database.makeHash("AGE_EXPLORATION")) {
// In Exploration Age
}
// Placement rules
const validLocation = Game.PlacementRules.getValidOceanNavalLocation(playerId);
// Economic rules (adjust for game speed)
const adjustedGold = Game.EconomicRules.adjustForGameSpeed(3000);| Property | Type | Description |
|---|---|---|
Game.age |
Hash | Current age hash |
Game.turn |
Integer | Current turn number |
Game.PlacementRules |
Object | Placement validation methods |
Game.EconomicRules |
Object | Economy adjustment methods |
Access database tables directly through GameInfo:
// Iterate all entries in a table
for (const resource of GameInfo.Resources) {
console.log(resource.ResourceType);
}
// Lookup by type string
const unitInfo = GameInfo.Units.lookup("UNIT_WARRIOR");
// Lookup by hash
const hash = Database.makeHash("UNIT_WARRIOR");
const unitInfo = GameInfo.Units.lookup(hash);
// Get metadata
const resourceInfo = GameInfo.Resources.lookup(resourceType);
const index = resourceInfo.$index; // Internal index
const typeHash = resourceInfo.$hash; // Type hash| Table | Content |
|---|---|
GameInfo.Units |
Unit definitions |
GameInfo.Buildings |
Building definitions |
GameInfo.Civilizations |
Civilization definitions |
GameInfo.Leaders |
Leader definitions |
GameInfo.Resources |
Resource definitions |
GameInfo.Features |
Map feature definitions |
GameInfo.Feature_NaturalWonders |
Natural wonder list |
GameInfo.Technologies |
Technology definitions |
GameInfo.Civics |
Civic definitions |
GameInfo.Ages |
Age definitions |
GameInfo.Resource_Distribution |
Resource placement rules |
GameInfo.Unit_ShadowReplacements |
Unit upgrades for age transitions |
GameInfo.MapIslandBehavior |
Island map behavior |
GameInfo.Terrains |
Terrain definitions |
GameInfo.Biomes |
Biome definitions |
// Get specific player by ID
const player = Players.get(playerId);
// Get all ever-alive players (includes eliminated)
const playerList = Players.getEverAlive();
// Get local player
const localPlayer = Players.get(GameContext.localObserverID);
// Iterate all players
for (const player of Players.getEverAlive()) {
if (player.isAlive) {
console.log("Active player:", player.id);
}
}const player = Players.get(playerId);
// Basic info
player.id // Player ID
player.civilizationType // Civilization hash
player.leaderType // Leader hash
player.isAlive // Is still in game
player.isMajor // Is major civilization
player.isHuman // Is human player
// Player components (sub-objects)
player.Cities // City management
player.Units // Unit management
player.Treasury // Gold balance
player.DiplomacyTreasury // Influence balance
player.AdvancedStart // Age transition cards
player.Diplomacy // Diplomatic relations
// Custom properties (for mods)
player.getProperty("PROPERTY_NAME");
player.setProperty("PROPERTY_NAME", value);const cities = player.Cities;
// Get city IDs
const cityIds = cities.getCityIds();
// Get cities collection
const cityList = cities.getCities();
// Get capital
const capital = cities.getCapital();
// Find closest city to location
const nearest = cities.findClosest(location);
// City count
const count = cities.getCityCount();const units = player.Units;
// Get all unit IDs
const unitIds = units.getUnitIds();
// Get buildable unit type (considering unlocks)
const unitType = units.getBuildUnit("UNIT_WARRIOR");
// Unit shadows (for age transitions)
const shadows = units.getUnitShadows();// Get unit by ID
const unit = Units.get(unitId);
// Create a unit
const result = Units.create(playerId, {
Type: unitType, // Unit type hash or string
Location: location, // {x, y} or plot index
Validate: true // Validate placement (optional)
});
if (result.Success && result.ID) {
console.log("Created unit:", result.ID);
const newUnit = Units.get(result.ID);
}
// Move unit to location
Units.setLocation(unitId, newLocation);
// Delete unit
Units.destroy(unitId);const unit = Units.get(unitId);
// Basic info
unit.id // Unit ID
unit.name // Display name
unit.type // Unit type hash
unit.location // Current location {x, y}
unit.owner // Owner player ID
unit.movementPoints // Remaining movement
unit.maxMovementPoints // Maximum movement
// Army/commander info
unit.armyId // Army ID (if in army)
unit.isCommanderUnit // Is a commander
unit.isArmyCommander // Is army commander
unit.isFleetCommander // Is fleet commander
// Components
unit.Experience // Experience component
unit.Combat // Combat component
// Custom properties (for mods)
unit.getProperty("PROPERTY_NAME");
unit.setProperty("PROPERTY_NAME", value);// Get army by ID
const army = Armies.get(armyId);
// Army properties
army.id // Army ID
army.commanderId // Commander unit ID
army.location // Current location
// Get units in army
const unitIds = army.getUnitIds();
// Create army with commander
const result = Armies.create(playerId, commanderUnitId);// Get city by ID
const city = Cities.get(cityId);
// Basic info
city.id // City ID
city.name // City name
city.location // Location {x, y}
city.owner // Owner player ID
city.population // Current population
city.isCapital // Is capital city
city.isTown // Is a town (no build queue)
// Components
city.Trade // Trade component
city.Production // Production component
city.Growth // Growth component
// Trade connection check
city.Trade?.isConnectedToOwnersCapitalByLand();
city.Trade?.isConnectedToOwnersCapitalBySea();
// Change settlement type
city.changeHasBuildQueue(-1); // Regress to town
city.changeHasBuildQueue(1); // Upgrade to city// Map dimensions
const width = GameplayMap.getGridWidth();
const height = GameplayMap.getGridHeight();
const totalPlots = GameplayMap.getPlotCount();
// Plot queries by coordinates
const terrain = GameplayMap.getTerrainType(x, y);
const resource = GameplayMap.getResourceType(x, y);
const feature = GameplayMap.getFeatureType(x, y);
const biome = GameplayMap.getBiomeType(x, y);
const elevation = GameplayMap.getElevation(x, y);
const continent = GameplayMap.getContinentType(x, y);
// Hemisphere info
const hemisphere = GameplayMap.getHemisphere(x);
const primaryHemisphere = GameplayMap.getPrimaryHemisphere();
// Landmass info
const landmassId = GameplayMap.getLandmassId(x, y);
const landmassRegionId = GameplayMap.getLandmassRegionId(x, y);
// Index conversions
const index = GameplayMap.getIndexFromXY(x, y);
const location = GameplayMap.getLocationFromIndex(index);
// Adjacency
const neighbors = GameplayMap.getAdjacentPlots(x, y);
// Visibility
const isVisible = GameplayMap.isPlotVisible(playerId, x, y);
const isRevealed = GameplayMap.isPlotRevealed(playerId, x, y);
// Random (deterministic from seed)
const seed = GameplayMap.getRandomSeed();For map generation scripts:
// Set terrain
TerrainBuilder.setTerrainType(x, y, terrainType);
TerrainBuilder.setBiomeType(x, y, biomeType);
TerrainBuilder.setElevation(x, y, elevation);
// Set features
TerrainBuilder.setFeatureType(x, y, featureType);
TerrainBuilder.canHaveFeature(x, y, featureType);
// Feature with parameters
TerrainBuilder.setFeatureType(x, y, featureParam);
TerrainBuilder.canHaveFeatureParam(x, y, featureParam);
// Generate procedural maps
TerrainBuilder.generatePoissonMap(seed, avgDistance, smoothing);
TerrainBuilder.generateFractal(seed, octaves, persistence);
// Random numbers (seeded)
const roll = TerrainBuilder.getRandomNumber(max, "description");
// Store data for later processing
TerrainBuilder.storeWaterData();
// Continent assignment
TerrainBuilder.setContinentType(x, y, continentType);// Set resources
ResourceBuilder.setResourceType(x, y, resourceType);
ResourceBuilder.canHaveResource(x, y, resourceType, strict);
// Query resources
const counts = ResourceBuilder.getResourceCounts(playerId); // -1 for all players
const generated = ResourceBuilder.getGeneratedMapResources();
// Age validation
ResourceBuilder.isResourceValidForAge(resourceType, ageType);
ResourceBuilder.isResourceRequiredForAge(resourceType, ageType);
ResourceBuilder.isResourceClassRequiredForLegacyPath(resourceType);
// Landmass assignment
ResourceBuilder.getResourceLandmass(resourceIndex);
// Resource balancing
const cuts = ResourceBuilder.getBestMapResourceCuts(newResources, numToCut);// Create hash from string
const hash = Database.makeHash("TYPE_STRING");
// Compare with database values
if (Game.age == Database.makeHash("AGE_EXPLORATION")) {
// In Exploration Age
}
if (player.civilizationType == Database.makeHash("CIVILIZATION_ROME")) {
// Playing as Rome
}// Game configuration
const speed = Configuration.getGameValue("SpeedType");
const difficulty = Configuration.getGameValue("Handicap");
const mapSize = Configuration.getGameValue("MapSize");
// Map configuration
const mapScript = Configuration.getMapValue("Script");
const requests = Configuration.getMapValue("RequestedNaturalWonders");
const temperature = Configuration.getMapValue("Temperature");
const rainfall = Configuration.getMapValue("Rainfall");
// User configuration
const userConfig = Configuration.getUser();
userConfig.firstTimeTutorialEnabled;
userConfig.setFirstTimeTutorialEnabled(false);
userConfig.saveCheckpoint();// Compose localized text from LOC key
const text = Locale.compose("LOC_UNIT_WARRIOR_NAME"); // "Warrior"
// With parameters
const text = Locale.compose("LOC_CITY_FOUNDED", cityName);// Console logging (appears in logs)
console.log("Info message");
console.warn("Warning message");
console.error("Error message");
// Debug with values
console.log("Player ID:", playerId, "City count:", cityCount);Logs appear in: %LOCALAPPDATA%\Firaxis Games\Sid Meier's Civilization VII\Logs\
Scripts use ES6 module imports:
// Import from other modules
import { functionName } from '../path/to/module.js';
import { shuffle, randomElement } from './map-utilities.js';
import * as MapUtils from './map-utilities.js';
// Export functions for use by other scripts
export function myFunction() { }
export const myVariable = 42;
export { myFunction, myVariable };
// Default export
export default class MyClass { }UI scripts use custom DOM events:
// Creating custom events
class MyEvent extends CustomEvent {
constructor(data) {
super("my-event-name", {
bubbles: true,
cancelable: true,
detail: { data }
});
}
}
// Dispatching events
window.dispatchEvent(new CustomEvent("user-interface-loaded-and-ready"));
window.dispatchEvent(new MyEvent({ value: 42 }));
// Listening for events
window.addEventListener("engine-input", handleInput);
window.addEventListener("my-event-name", (event) => {
console.log("Received:", event.detail);
});import { InterfaceMode } from '../interface-modes/interface-modes.js';
// Switch interface mode
InterfaceMode.switchTo("INTERFACEMODE_DEFAULT");
InterfaceMode.switchTo("INTERFACEMODE_PAUSE_MENU");
InterfaceMode.switchTo("INTERFACEMODE_SCREENSHOT");
InterfaceMode.switchTo("INTERFACEMODE_SELECTION");
// Check current mode
if (InterfaceMode.isInInterfaceMode("INTERFACEMODE_PAUSE_MENU")) {
// Game is paused
}
// Register custom mode handler
class MyInterfaceMode {
transitionTo(oldMode, newMode, context) {
// Called when switching to this mode
console.log("Entering my mode from:", oldMode);
}
transitionFrom(oldMode, newMode) {
// Called when leaving this mode
console.log("Leaving my mode for:", newMode);
}
allowsHotKeys() {
return true; // Allow hotkeys in this mode
}
handleInput(inputData) {
// Handle input while in this mode
return false; // Return true if handled
}
}
InterfaceMode.addHandler("INTERFACEMODE_MY_MODE", new MyInterfaceMode());const width = GameplayMap.getGridWidth();
const height = GameplayMap.getGridHeight();
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const terrain = GameplayMap.getTerrainType(x, y);
// Process each plot
}
}function findValidCityLocation(playerId) {
const player = Players.get(playerId);
const capital = player.Cities.getCapital();
// Search outward from capital
const neighbors = GameplayMap.getAdjacentPlots(capital.location.x, capital.location.y);
for (const plot of neighbors) {
if (isValidForCity(plot.x, plot.y)) {
return plot;
}
}
return null;
}// Use optional chaining for components that may not exist
const isConnected = city.Trade?.isConnectedToOwnersCapitalByLand() ?? false;
// Check before accessing
if (player.Diplomacy) {
const relations = player.Diplomacy.getRelationsWith(otherPlayerId);
}try {
const result = Units.create(playerId, { Type: unitType, Location: loc });
if (!result.Success) {
console.error("Failed to create unit:", result.Error);
}
} catch (error) {
console.error("Exception creating unit:", error);
}- Creating a Map Generator - Map script tutorial
- Creating UI Extensions - UI modding tutorial
- modinfo Files - Script loading configuration
- XML Reference - Database reference