Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_resource_field.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_resource_field.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_resource_field.xml (revision 26015)
@@ -1,73 +1,70 @@
50
100
2.0
250
decay|rubble/rubble_field
Field
template_structure_resource_field
Field
Harvest grain for food. Each subsequent gatherer works less efficiently.
structures/field.png
50
false
false
-
-
15
40
5
false
Infinity
food.grain
5
0.90
interface/complete/building/complete_field.xml
8.0
-
0
structures/plot_field_found.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special_rotarymill.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special_rotarymill.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special_rotarymill.xml (revision 26015)
@@ -1,59 +1,56 @@
100
200
100
6.0
2000
Rotary Mill
template_structure_special_rotarymill
RotaryMill
structures/rotarymill.png
40
20
-
-
food
true
interface/complete/building/complete_ffactri.xml
8.0
false
32
40000
-
40
structures/fndn_6x6.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_barracks.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_barracks.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_barracks.xml (revision 26015)
@@ -1,81 +1,82 @@
structures/xp_trickle
150
200
100
12.0
10
Infantry Cavalry
2000
decay|rubble/rubble_stone_4x4
Barracks
template_structure_military_barracks
Train Infantry and research Infantry technologies.
Village Barracks
structures/barracks.png
phase_village
40
20
+
barracks_batch_training
infantry_cost_time
unlock_champion_infantry
pair_unlock_champions_sele
interface/complete/building/complete_barracks.xml
0.8
units/{civ}/infantry_spearman_b
units/{civ}/infantry_pikeman_b
units/{civ}/infantry_maceman_b
units/{civ}/infantry_axeman_b
units/{civ}/infantry_swordsman_b
units/{civ}/infantry_javelineer_b
units/{civ}/infantry_slinger_b
units/{civ}/infantry_archer_b
units/{civ}/champion_infantry_spearman
units/{civ}/champion_infantry_pikeman
units/{civ}/champion_infantry_maceman
units/{civ}/champion_infantry_axeman
units/{civ}/champion_infantry_swordsman
units/{civ}/champion_infantry_javelineer
units/{civ}/champion_infantry_slinger
units/{civ}/champion_infantry_archer
32
structures/fndn_6x6.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_elephant_stable.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_elephant_stable.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_elephant_stable.xml (revision 26015)
@@ -1,63 +1,64 @@
structures/xp_trickle
180
200
200
8.0
5
Elephant
3000
decay|rubble/rubble_stone_6x6
Elephant Stable
template_structure_military_elephant_stable
Train Elephants and research Elephant technologies.
City ElephantStable
phase_city
structures/stable_elephant.png
40
40
+
interface/complete/building/complete_elephant_stable.xml
38
0.7
units/{civ}/support_elephant
units/{civ}/elephant_archer_b
units/{civ}/champion_elephant
40
structures/fndn_9x8.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_forge.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_forge.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_forge.xml (revision 26015)
@@ -1,70 +1,71 @@
120
200
12.0
1
Infantry Healer
2000
decay|rubble/rubble_stone_4x4
Forge
template_structure_military_forge
Research attack damage and damage resistance technologies.
-ConquestCritical
Town Forge
structures/blacksmith.png
phase_town
40
+
soldier_attack_melee_01
soldier_attack_melee_02
soldier_attack_melee_03
soldier_attack_melee_03_variant
soldier_attack_ranged_01
soldier_attack_ranged_02
soldier_attack_ranged_03
soldier_resistance_hack_01
soldier_resistance_hack_02
soldier_resistance_hack_03
soldier_resistance_pierce_01
soldier_resistance_pierce_02
soldier_resistance_pierce_03
archer_attack_spread
interface/complete/building/complete_forge.xml
38
30000
32
structures/fndn_5x5.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_range.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_range.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_range.xml (revision 26015)
@@ -1,55 +1,56 @@
120
200
12.0
10
Infantry
2000
decay|rubble/rubble_stone_5x5
Practice Range
template_structure_military_range
Train Ranged Infantry and research technologies.
Village Range
structures/range.png
phase_village
40
+
interface/complete/building/complete_range.xml
0.8
units/{civ}/infantry_javelineer_b
units/{civ}/infantry_slinger_b
units/{civ}/infantry_archer_b
32
structures/fndn_7x7.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_resource_corral.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_resource_corral.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_resource_corral.xml (revision 26015)
@@ -1,69 +1,70 @@
50
100
5.0
500
decay|rubble/rubble_stone_3x3
Corral
template_structure_resource_corral
Raise Domestic Animals for food.
Economic Village Corral
structures/corral.png
phase_village
20
+
gather_animals_stockbreeding
20
interface/complete/building/complete_corral.xml
false
20
30000
0.7
gaia/fauna_goat_trainable
gaia/fauna_sheep_trainable
gaia/fauna_pig_trainable
gaia/fauna_cattle_cow_trainable
20
structures/fndn_3x3.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special_library.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special_library.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special_library.xml (revision 26015)
@@ -1,57 +1,54 @@
structures/library
Library
200
200
200
9.0
2000
decay|rubble/rubble_stone_4x6
Library
template_structure_special_library
Library
structures/library_scroll.png
40
40
-
-
interface/complete/building/complete_library.xml
false
50
40000
-
40
structures/fndn_7x9.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_wonder.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_wonder.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_wonder.xml (revision 26015)
@@ -1,94 +1,95 @@
structures/wonder_population_cap
Wonder
4
1000
1000
1500
1000
10.0
50
0.1
Unit
Support Soldier
5
2
5000
decay|rubble/rubble_stone_6x6
Wonder
template_structure_wonder
Bring glory to your civilization and add large tracts of land to your empire.
ConquestCritical
City Wonder
structures/wonder.png
phase_city
200
300
200
+
wonder_population_cap
15
25
3
1.0
1.0
1.0
1.0
2000
interface/complete/building/complete_wonder.xml
true
100
65535
72
structures/fndn_9x9.xml
Index: ps/trunk/binaries/data/mods/public/simulation/components/ProductionQueue.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/components/ProductionQueue.js (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/components/ProductionQueue.js (revision 26015)
@@ -1,518 +1,528 @@
function ProductionQueue() {}
ProductionQueue.prototype.Schema =
"Helps the building to train new units and research technologies." +
"";
ProductionQueue.prototype.ProgressInterval = 1000;
ProductionQueue.prototype.MaxQueueSize = 16;
/**
* This object represents an item in the queue.
*/
ProductionQueue.prototype.Item = function() {};
/**
* @param {number} producer - The entity ID of our producer.
* @param {string} metadata - Optionally any metadata attached to us.
*/
ProductionQueue.prototype.Item.prototype.Init = function(producer, metadata)
{
this.producer = producer;
this.metadata = metadata;
+};
+/**
+ * @param {string} type - The type of queue to use.
+ * @param {string} templateName - The template to queue.
+ * @param {number} count - The amount of template to queue. Only applicable for type == "unit".
+ *
+ * @return {boolean} - Whether the item could be queued.
+ */
+ProductionQueue.prototype.Item.prototype.Queue = function(type, templateName, count)
+{
+ if (type == "unit")
+ return this.QueueEntity(templateName, count);
+
+ if (type == "technology")
+ return this.QueueTechnology(templateName);
+
+ warn("Tried to add invalid item of type \"" + type + "\" and template \"" + templateName + "\" to a production queue (entity: " + this.producer + ").");
+ return false;
};
+/**
+ * @param {string} templateName - The name of the entity to queue.
+ * @param {number} count - The number of entities that should be produced.
+ * @return {boolean} - Whether the batch was successfully created.
+ */
ProductionQueue.prototype.Item.prototype.QueueEntity = function(templateName, count)
{
const cmpTrainer = Engine.QueryInterface(this.producer, IID_Trainer);
if (!cmpTrainer)
return false;
this.entity = cmpTrainer.QueueBatch(templateName, count, this.metadata);
if (this.entity == -1)
return false;
this.originalItem = {
"templateName": templateName,
"count": count,
"metadata": this.metadata
};
return true;
};
+/**
+ * @param {string} templateName - The name of the technology to queue.
+ * @return {boolean} - Whether the technology was successfully queued.
+ */
ProductionQueue.prototype.Item.prototype.QueueTechnology = function(templateName)
{
const cmpResearcher = Engine.QueryInterface(this.producer, IID_Researcher);
if (!cmpResearcher)
return false;
this.technology = cmpResearcher.QueueTechnology(templateName, this.metadata);
- if (this.technology == -1)
- return false;
-
- return true;
+ return this.technology != -1;
};
/**
- * @param {number} id - The id of this item.
+ * @param {number} id - The id this item needs to get.
*/
ProductionQueue.prototype.Item.prototype.SetID = function(id)
{
this.id = id;
};
ProductionQueue.prototype.Item.prototype.Stop = function()
{
- if (this.entity)
- {
- const cmpTrainer = Engine.QueryInterface(this.producer, IID_Trainer);
- if (cmpTrainer)
- cmpTrainer.StopBatch(this.entity);
- }
+ if (this.entity > 0)
+ Engine.QueryInterface(this.producer, IID_Trainer)?.StopBatch(this.entity);
- if (this.technology)
- {
- const cmpResearcher = Engine.QueryInterface(this.producer, IID_Researcher);
- if (cmpResearcher)
- cmpResearcher.StopResearching(this.technology);
- }
+ if (this.technology > 0)
+ Engine.QueryInterface(this.producer, IID_Researcher)?.StopResearching(this.technology);
};
/**
* Called when the first work is performed.
*/
ProductionQueue.prototype.Item.prototype.Start = function()
{
this.started = true;
};
+/**
+ * @return {boolean} - Whether there is work done on the item.
+ */
ProductionQueue.prototype.Item.prototype.IsStarted = function()
{
return !!this.started;
};
/**
* @return {boolean} - Whether this item is finished.
*/
ProductionQueue.prototype.Item.prototype.IsFinished = function()
{
return !!this.finished;
};
/**
* @param {number} allocatedTime - The time allocated to this item.
* @return {number} - The time used for this item.
*/
ProductionQueue.prototype.Item.prototype.Progress = function(allocatedTime)
{
if (this.entity)
{
const cmpTrainer = Engine.QueryInterface(this.producer, IID_Trainer);
allocatedTime -= cmpTrainer.Progress(this.entity, allocatedTime);
if (!cmpTrainer.HasBatch(this.entity))
delete this.entity;
}
if (this.technology)
{
const cmpResearcher = Engine.QueryInterface(this.producer, IID_Researcher);
allocatedTime -= cmpResearcher.Progress(this.technology, allocatedTime);
if (!cmpResearcher.HasItem(this.technology))
delete this.technology;
}
if (!this.entity && !this.technology)
this.finished = true;
return allocatedTime;
};
ProductionQueue.prototype.Item.prototype.Pause = function()
{
this.paused = true;
if (this.entity)
Engine.QueryInterface(this.producer, IID_Trainer).PauseBatch(this.entity);
if (this.technology)
Engine.QueryInterface(this.producer, IID_Researcher).PauseTechnology(this.technology);
};
ProductionQueue.prototype.Item.prototype.Unpause = function()
{
delete this.paused;
if (this.entity)
Engine.QueryInterface(this.producer, IID_Trainer).UnpauseBatch(this.entity);
if (this.technology)
Engine.QueryInterface(this.producer, IID_Researcher).UnpauseTechnology(this.technology);
};
+/**
+ * @return {boolean} - Whether the item is currently paused.
+ */
ProductionQueue.prototype.Item.prototype.IsPaused = function()
{
return !!this.paused;
};
/**
* @return {Object} - Some basic information of this item.
*/
ProductionQueue.prototype.Item.prototype.GetBasicInfo = function()
{
let result;
if (this.technology)
result = Engine.QueryInterface(this.producer, IID_Researcher).GetResearchingTechnology(this.technology);
else if (this.entity)
result = Engine.QueryInterface(this.producer, IID_Trainer).GetBatch(this.entity);
result.id = this.id;
result.paused = this.paused;
return result;
};
/**
* @return {Object} - The originally queued item.
*/
ProductionQueue.prototype.Item.prototype.OriginalItem = function()
{
return this.originalItem;
};
ProductionQueue.prototype.Item.prototype.Serialize = function()
{
return {
"id": this.id,
"metadata": this.metadata,
"paused": this.paused,
"producer": this.producer,
"entity": this.entity,
"technology": this.technology,
"started": this.started,
"originalItem": this.originalItem
};
};
ProductionQueue.prototype.Item.prototype.Deserialize = function(data)
{
this.Init(data.producer, data.metadata);
this.id = data.id;
this.paused = data.paused;
this.entity = data.entity;
this.technology = data.technology;
this.started = data.started;
this.originalItem = data.originalItem;
};
ProductionQueue.prototype.Init = function()
{
this.nextID = 1;
-
this.queue = [];
};
ProductionQueue.prototype.Serialize = function()
{
const queue = [];
for (const item of this.queue)
queue.push(item.Serialize());
return {
"autoqueuing": this.autoqueuing,
"nextID": this.nextID,
"paused": this.paused,
"timer": this.timer,
"queue": queue
};
};
ProductionQueue.prototype.Deserialize = function(data)
{
this.Init();
this.autoqueuing = data.autoqueuing;
this.nextID = data.nextID;
this.paused = data.paused;
this.timer = data.timer;
for (const item of data.queue)
{
const newItem = new this.Item();
newItem.Deserialize(item);
this.queue.push(newItem);
}
};
/**
* @return {boolean} - Whether we are automatically queuing items.
*/
ProductionQueue.prototype.IsAutoQueueing = function()
{
return !!this.autoqueuing;
};
/**
* Turn on Auto-Queue.
*/
ProductionQueue.prototype.EnableAutoQueue = function()
{
this.autoqueuing = true;
};
/**
* Turn off Auto-Queue.
*/
ProductionQueue.prototype.DisableAutoQueue = function()
{
delete this.autoqueuing;
};
/*
* Adds a new batch of identical units to train or a technology to research to the production queue.
* @param {string} templateName - The template to start production on.
* @param {string} type - The type of production (i.e. "unit" or "technology").
* @param {number} count - The amount of units to be produced. Ignored for a tech.
* @param {any} metadata - Optionally any metadata to be attached to the item.
* @param {boolean} pushFront - Whether to push the item to the front of the queue and pause any item(s) currently in progress.
*
* @return {boolean} - Whether the addition of the item has succeeded.
*/
ProductionQueue.prototype.AddItem = function(templateName, type, count, metadata, pushFront = false)
{
// TODO: there should be a way for the GUI to determine whether it's going
// to be possible to add a batch (based on resource costs and length limits).
if (!this.queue.length)
{
const cmpPlayer = QueryOwnerInterface(this.entity);
if (!cmpPlayer)
return false;
const player = cmpPlayer.GetPlayerID();
const cmpUpgrade = Engine.QueryInterface(this.entity, IID_Upgrade);
if (cmpUpgrade && cmpUpgrade.IsUpgrading())
{
let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
cmpGUIInterface.PushNotification({
"players": [player],
"message": markForTranslation("Entity is being upgraded. Cannot start production."),
"translateMessage": true
});
return false;
}
}
else if (this.queue.length >= this.MaxQueueSize)
{
const cmpPlayer = QueryOwnerInterface(this.entity);
if (!cmpPlayer)
return false;
const player = cmpPlayer.GetPlayerID();
const cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
cmpGUIInterface.PushNotification({
"players": [player],
"message": markForTranslation("The production queue is full."),
"translateMessage": true,
});
return false;
}
const item = new this.Item();
item.Init(this.entity, metadata);
- if (type == "unit")
- {
- if (!item.QueueEntity(templateName, count))
- return false;
- }
- else if (type == "technology")
- {
- if (!item.QueueTechnology(templateName))
- return false;
- }
- else
- {
- warn("Tried to add invalid item of type \"" + type + "\" and template \"" + templateName + "\" to a production queue");
+ if (!item.Queue(type, templateName, count))
return false;
- }
item.SetID(this.nextID++);
if (pushFront)
{
this.queue[0]?.Pause();
this.queue.unshift(item);
}
else
this.queue.push(item);
Engine.PostMessage(this.entity, MT_ProductionQueueChanged, null);
if (!this.timer)
this.StartTimer();
return true;
};
/*
- * Removes an item from the queue.
+ * @param {number} - The ID of the item to remove from the queue.
*/
ProductionQueue.prototype.RemoveItem = function(id)
{
let itemIndex = this.queue.findIndex(item => item.id == id);
if (itemIndex == -1)
return;
this.queue.splice(itemIndex, 1)[0].Stop();
Engine.PostMessage(this.entity, MT_ProductionQueueChanged, null);
if (!this.queue.length)
this.StopTimer();
};
ProductionQueue.prototype.SetAnimation = function(name)
{
let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
if (cmpVisual)
cmpVisual.SelectAnimation(name, false, 1);
};
/*
* Returns basic data from all batches in the production queue.
*/
ProductionQueue.prototype.GetQueue = function()
{
return this.queue.map(item => item.GetBasicInfo());
};
/*
* Removes all existing batches from the queue.
*/
ProductionQueue.prototype.ResetQueue = function()
{
while (this.queue.length)
this.RemoveItem(this.queue[0].id);
this.DisableAutoQueue();
};
/*
* Increments progress on the first item in the production queue.
* @param {Object} data - Unused in this case.
* @param {number} lateness - The time passed since the expected time to fire the function.
*/
ProductionQueue.prototype.ProgressTimeout = function(data, lateness)
{
if (this.paused)
return;
// Allocate available time to as many queue items as it takes
// until we've used up all the time (so that we work accurately
// with items that take fractions of a second).
let time = this.ProgressInterval + lateness;
while (this.queue.length)
{
let item = this.queue[0];
if (item.IsPaused())
item.Unpause();
if (!item.IsStarted())
{
if (item.entity)
this.SetAnimation("training");
if (item.technology)
this.SetAnimation("researching");
item.Start();
}
time -= item.Progress(time);
if (!item.IsFinished())
{
Engine.PostMessage(this.entity, MT_ProductionQueueChanged, null);
return;
}
this.queue.shift();
Engine.PostMessage(this.entity, MT_ProductionQueueChanged, null);
// If autoqueuing, push a new unit on the queue immediately,
// but don't start right away. This 'wastes' some time, making
// autoqueue slightly worse than regular queuing, and also ensures
// that autoqueue doesn't train more than one item per turn,
// if the units would take fewer than ProgressInterval ms to train.
if (this.autoqueuing)
{
const autoqueueData = item.OriginalItem();
if (!autoqueueData)
continue;
if (!this.AddItem(autoqueueData.templateName, "unit", autoqueueData.count, autoqueueData.metadata))
{
this.DisableAutoQueue();
const cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
cmpGUIInterface.PushNotification({
"players": [QueryOwnerInterface(this.entity).GetPlayerID()],
"message": markForTranslation("Could not auto-queue unit, de-activating."),
"translateMessage": true
});
}
break;
}
}
if (!this.queue.length)
this.StopTimer();
};
ProductionQueue.prototype.PauseProduction = function()
{
this.StopTimer();
this.paused = true;
this.queue[0]?.Pause();
- this.StopTimer();
};
ProductionQueue.prototype.UnpauseProduction = function()
{
this.queue[0]?.Unpause();
delete this.paused;
this.StartTimer();
};
ProductionQueue.prototype.StartTimer = function()
{
if (this.timer)
return;
this.timer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer).SetInterval(
this.entity,
IID_ProductionQueue,
"ProgressTimeout",
this.ProgressInterval,
this.ProgressInterval,
null
);
};
ProductionQueue.prototype.StopTimer = function()
{
if (!this.timer)
return;
this.SetAnimation("idle");
Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer).CancelTimer(this.timer);
delete this.timer;
};
+/**
+ * @return {boolean} - Whether this entity is currently producing.
+ */
ProductionQueue.prototype.HasQueuedProduction = function()
{
return this.queue.length > 0;
};
ProductionQueue.prototype.OnOwnershipChanged = function(msg)
{
// Reset the production queue whenever the owner changes.
// (This should prevent players getting surprised when they capture
// an enemy building, and then loads of the enemy's civ's soldiers get
// created from it. Also it means we don't have to worry about
// updating the reserved pop slots.)
this.ResetQueue();
};
ProductionQueue.prototype.OnGarrisonedStateChanged = function(msg)
{
if (msg.holderID != INVALID_ENTITY)
this.PauseProduction();
else
this.UnpauseProduction();
};
Engine.RegisterComponentType(IID_ProductionQueue, "ProductionQueue", ProductionQueue);
Index: ps/trunk/binaries/data/mods/public/simulation/components/Researcher.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/components/Researcher.js (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/components/Researcher.js (revision 26015)
@@ -1,447 +1,446 @@
function Researcher() {}
Researcher.prototype.Schema =
"Allows the entity to research technologies." +
"" +
"" +
"0.5" +
"0.1" +
"0" +
"2" +
"" +
"" +
"" +
"\n phase_town_{civ}\n phase_metropolis_ptol\n unlock_shared_los\n wonder_population_cap\n " +
"" +
"" +
"" +
"" +
"" +
"tokens" +
"" +
"" +
"" +
"" +
"" +
"" +
Resources.BuildSchema("nonNegativeDecimal", ["time"]) +
"" +
"";
/**
* This object represents a technology being researched.
*/
Researcher.prototype.Item = function() {};
/**
* @param {string} templateName - The name of the template we ought to research.
* @param {number} researcher - The entity ID of our researcher.
* @param {string} metadata - Optionally any metadata to attach to us.
*/
Researcher.prototype.Item.prototype.Init = function(templateName, researcher, metadata)
{
this.templateName = templateName;
this.researcher = researcher;
this.metadata = metadata;
};
/**
* Prepare for the queue.
* @param {Object} techCostMultiplier - The multipliers to use when calculating costs.
* @return {boolean} - Whether the item was successfully initiated.
*/
Researcher.prototype.Item.prototype.Queue = function(techCostMultiplier)
{
const template = TechnologyTemplates.Get(this.templateName);
if (!template)
return false;
this.resources = {};
if (template.cost)
for (const res in template.cost)
this.resources[res] = Math.floor((techCostMultiplier[res] === undefined ? 1 : techCostMultiplier[res]) * template.cost[res]);
const cmpPlayer = QueryOwnerInterface(this.researcher);
// TrySubtractResources should report error to player (they ran out of resources).
if (!cmpPlayer?.TrySubtractResources(this.resources))
return false;
this.player = cmpPlayer.GetPlayerID();
const time = (techCostMultiplier.time || 1) * (template.researchTime || 0) * 1000;
this.timeRemaining = time;
this.timeTotal = time;
// Tell the technology manager that we have queued researching this
// such that players can't research the same thing twice.
const cmpTechnologyManager = QueryPlayerIDInterface(this.player, IID_TechnologyManager);
cmpTechnologyManager.QueuedResearch(this.templateName, this.researcher);
return true;
};
Researcher.prototype.Item.prototype.Stop = function()
{
const cmpTechnologyManager = QueryPlayerIDInterface(this.player, IID_TechnologyManager);
if (cmpTechnologyManager)
cmpTechnologyManager.StoppedResearch(this.templateName, true);
QueryPlayerIDInterface(this.player)?.RefundResources(this.resources);
delete this.resources;
};
/**
* Called when the first work is performed.
*/
Researcher.prototype.Item.prototype.Start = function()
{
const cmpTechnologyManager = QueryPlayerIDInterface(this.player, IID_TechnologyManager);
cmpTechnologyManager.StartedResearch(this.templateName, true);
this.started = true;
};
Researcher.prototype.Item.prototype.Finish = function()
{
const cmpTechnologyManager = QueryPlayerIDInterface(this.player, IID_TechnologyManager);
cmpTechnologyManager.ResearchTechnology(this.templateName);
const template = TechnologyTemplates.Get(this.templateName);
if (template?.soundComplete)
Engine.QueryInterface(SYSTEM_ENTITY, IID_SoundManager)?.PlaySoundGroup(template.soundComplete, this.researcher);
this.finished = true;
};
/**
* @param {number} allocatedTime - The time allocated to this item.
* @return {number} - The time used for this item.
*/
Researcher.prototype.Item.prototype.Progress = function(allocatedTime)
{
if (!this.started)
this.Start();
if (this.timeRemaining > allocatedTime)
{
this.timeRemaining -= allocatedTime;
return allocatedTime;
}
this.Finish();
return this.timeRemaining;
};
Researcher.prototype.Item.prototype.Pause = function()
{
this.paused = true;
};
Researcher.prototype.Item.prototype.Unpause = function()
{
delete this.paused;
};
/**
* @return {Object} - Some basic information of this item.
*/
Researcher.prototype.Item.prototype.GetBasicInfo = function()
{
return {
"technologyTemplate": this.templateName,
"progress": 1 - (this.timeRemaining / this.timeTotal),
"timeRemaining": this.timeRemaining,
"paused": this.paused,
"metadata": this.metadata
};
};
Researcher.prototype.Item.prototype.Serialize = function(id)
{
return {
"id": id,
"metadata": this.metadata,
"paused": this.paused,
"player": this.player,
"researcher": this.researcher,
"resource": this.resources,
"started": this.started,
"templateName": this.templateName,
"timeRemaining": this.timeRemaining,
"timeTotal": this.timeTotal,
};
};
Researcher.prototype.Item.prototype.Deserialize = function(data)
{
this.Init(data.templateName, data.researcher, data.metadata);
this.paused = data.paused;
this.player = data.player;
this.researcher = data.researcher;
this.resources = data.resources;
this.started = data.started;
this.timeRemaining = data.timeRemaining;
this.timeTotal = data.timeTotal;
};
Researcher.prototype.Init = function()
{
this.nextID = 1;
this.queue = new Map();
};
Researcher.prototype.Serialize = function()
{
const queue = [];
for (const [id, item] of this.queue)
queue.push(item.Serialize(id));
return {
"nextID": this.nextID,
"queue": queue
};
};
Researcher.prototype.Deserialize = function(data)
{
this.Init();
this.nextID = data.nextID;
for (const item of data.queue)
{
const newItem = new this.Item();
newItem.Deserialize(item);
this.queue.set(item.id, newItem);
}
};
/*
* Returns list of technologies that can be researched by this entity.
*/
Researcher.prototype.GetTechnologiesList = function()
{
if (!this.template.Technologies)
return [];
- let string = this.template.Technologies._string;
- string = ApplyValueModificationsToEntity("Researcher/Technologies/_string", string, this.entity);
+ const string = ApplyValueModificationsToEntity("Researcher/Technologies/_string", this.template.Technologies._string, this.entity);
if (!string)
return [];
const cmpTechnologyManager = QueryOwnerInterface(this.entity, IID_TechnologyManager);
if (!cmpTechnologyManager)
return [];
const cmpPlayer = QueryOwnerInterface(this.entity);
if (!cmpPlayer)
return [];
let techs = string.split(/\s+/);
// Replace the civ specific technologies.
for (let i = 0; i < techs.length; ++i)
{
const tech = techs[i];
if (tech.indexOf("{civ}") == -1)
continue;
const civTech = tech.replace("{civ}", cmpPlayer.GetCiv());
techs[i] = TechnologyTemplates.Has(civTech) ? civTech : tech.replace("{civ}", "generic");
}
// Remove any technologies that can't be researched by this civ.
techs = techs.filter(tech =>
cmpTechnologyManager.CheckTechnologyRequirements(
DeriveTechnologyRequirements(TechnologyTemplates.Get(tech), cmpPlayer.GetCiv()),
true));
const techList = [];
const superseded = {};
const disabledTechnologies = cmpPlayer.GetDisabledTechnologies();
// Add any top level technologies to an array which corresponds to the displayed icons.
// Also store what technology is superseded in the superseded object { "tech1":"techWhichSupercedesTech1", ... }.
for (const tech of techs)
{
if (disabledTechnologies && disabledTechnologies[tech])
continue;
const template = TechnologyTemplates.Get(tech);
if (!template.supersedes || techs.indexOf(template.supersedes) === -1)
techList.push(tech);
else
superseded[template.supersedes] = tech;
}
// Now make researched/in progress techs invisible.
for (const i in techList)
{
let tech = techList[i];
while (this.IsTechnologyResearchedOrInProgress(tech))
tech = superseded[tech];
techList[i] = tech;
}
const ret = [];
// This inserts the techs into the correct positions to line up the technology pairs.
for (let i = 0; i < techList.length; ++i)
{
const tech = techList[i];
if (!tech)
{
ret[i] = undefined;
continue;
}
const template = TechnologyTemplates.Get(tech);
if (template.top)
ret[i] = { "pair": true, "top": template.top, "bottom": template.bottom };
else
ret[i] = tech;
}
return ret;
};
/**
* @return {Object} - The multipliers to change the costs of any research with.
*/
Researcher.prototype.GetTechCostMultiplier = function()
{
const techCostMultiplier = {};
for (const res in this.template.TechCostMultiplier)
techCostMultiplier[res] = ApplyValueModificationsToEntity(
"Researcher/TechCostMultiplier/" + res,
+this.template.TechCostMultiplier[res],
this.entity);
return techCostMultiplier;
};
/**
* Checks whether we can research the given technology, minding paired techs.
*/
Researcher.prototype.IsTechnologyResearchedOrInProgress = function(tech)
{
if (!tech)
return false;
const cmpTechnologyManager = QueryOwnerInterface(this.entity, IID_TechnologyManager);
if (!cmpTechnologyManager)
return false;
const template = TechnologyTemplates.Get(tech);
if (template.top)
return cmpTechnologyManager.IsTechnologyResearched(template.top) ||
cmpTechnologyManager.IsInProgress(template.top) ||
cmpTechnologyManager.IsTechnologyResearched(template.bottom) ||
cmpTechnologyManager.IsInProgress(template.bottom);
return cmpTechnologyManager.IsTechnologyResearched(tech) || cmpTechnologyManager.IsInProgress(tech);
};
/**
* @param {string} templateName - The technology to queue.
* @param {string} metadata - Any metadata attached to the item.
* @return {number} - The ID of the item. -1 if the item could not be researched.
*/
Researcher.prototype.QueueTechnology = function(templateName, metadata)
{
if (!this.GetTechnologiesList().some(tech =>
tech && (tech == templateName ||
tech.pair && (tech.top == templateName || tech.bottom == templateName))))
{
error("This entity cannot research " + templateName + ".");
return -1;
}
const item = new this.Item();
item.Init(templateName, this.entity, metadata);
const techCostMultiplier = this.GetTechCostMultiplier();
if (!item.Queue(techCostMultiplier))
return -1;
const id = this.nextID++;
this.queue.set(id, item);
return id;
};
/**
* @param {number} id - The id of the technology researched here we need to stop.
*/
Researcher.prototype.StopResearching = function(id)
{
this.queue.get(id).Stop();
this.queue.delete(id);
};
/**
* @param {number} id - The id of the technology.
*/
Researcher.prototype.PauseTechnology = function(id)
{
this.queue.get(id).Pause();
};
/**
* @param {number} id - The id of the technology.
*/
Researcher.prototype.UnpauseTechnology = function(id)
{
this.queue.get(id).Unpause();
};
/**
* @param {number} id - The ID of the item to check.
* @return {boolean} - Whether we are currently training the item.
*/
Researcher.prototype.HasItem = function(id)
{
return this.queue.has(id);
};
/**
* @parameter {number} id - The id of the research.
* @return {Object} - Some basic information about the research.
*/
Researcher.prototype.GetResearchingTechnology = function(id)
{
return this.queue.get(id).GetBasicInfo();
};
/**
* @parameter {string} technologyName - The name of the research.
* @return {Object} - Some basic information about the research.
*/
Researcher.prototype.GetResearchingTechnologyByName = function(technologyName)
{
let techID;
for (const [id, value] of this.queue)
if (value.templateName === technologyName)
{
techID = id;
break;
}
if (!techID)
return undefined;
return this.GetResearchingTechnology(techID);
};
/**
* @param {number} id - The ID of the item we spent time on.
* @param {number} allocatedTime - The time we spent on the given item.
* @return {number} - The time we've actually used.
*/
Researcher.prototype.Progress = function(id, allocatedTime)
{
const item = this.queue.get(id);
const usedTime = item.Progress(allocatedTime);
if (item.finished)
this.queue.delete(id);
return usedTime;
};
Engine.RegisterComponentType(IID_Researcher, "Researcher", Researcher);
Index: ps/trunk/binaries/data/mods/public/simulation/components/Trainer.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/components/Trainer.js (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/components/Trainer.js (revision 26015)
@@ -1,727 +1,729 @@
function Trainer() {}
Trainer.prototype.Schema =
"Allows the entity to train new units." +
"" +
"0.7" +
"" +
"\n units/{civ}/support_female_citizen\n units/{native}/support_trader\n units/athen/infantry_spearman_b\n " +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"tokens" +
"" +
"" +
"" +
"";
/**
* This object represents a batch of entities being trained.
*/
Trainer.prototype.Item = function() {};
/**
* @param {string} templateName - The name of the template we ought to train.
* @param {number} count - The size of the batch to train.
* @param {number} trainer - The entity ID of our trainer.
* @param {string} metadata - Optionally any metadata to attach to us.
*/
Trainer.prototype.Item.prototype.Init = function(templateName, count, trainer, metadata)
{
this.count = count;
this.templateName = templateName;
this.trainer = trainer;
this.metadata = metadata;
};
/**
* Prepare for the queue.
* @param {Object} trainCostMultiplier - The multipliers to use when calculating costs.
* @param {number} batchTimeMultiplier - The factor to use when training this batches.
*
* @return {boolean} - Whether the item was successfully initiated.
*/
Trainer.prototype.Item.prototype.Queue = function(trainCostMultiplier, batchTimeMultiplier)
{
if (!Number.isInteger(this.count) || this.count <= 0)
{
error("Invalid batch count " + this.count + ".");
return false;
}
const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
const template = cmpTemplateManager.GetTemplate(this.templateName);
if (!template)
return false;
const cmpPlayer = QueryOwnerInterface(this.trainer);
if (!cmpPlayer)
return false;
this.player = cmpPlayer.GetPlayerID();
this.resources = {};
const totalResources = {};
for (const res in template.Cost.Resources)
{
this.resources[res] = (trainCostMultiplier[res] === undefined ? 1 : trainCostMultiplier[res]) *
ApplyValueModificationsToTemplate(
"Cost/Resources/" + res,
+template.Cost.Resources[res],
this.player,
template);
totalResources[res] = Math.floor(this.count * this.resources[res]);
}
// TrySubtractResources should report error to player (they ran out of resources).
if (!cmpPlayer.TrySubtractResources(totalResources))
return false;
this.population = ApplyValueModificationsToTemplate("Cost/Population", +template.Cost.Population, this.player, template);
if (template.TrainingRestrictions)
{
const unitCategory = template.TrainingRestrictions.Category;
const cmpPlayerEntityLimits = QueryPlayerIDInterface(this.player, IID_EntityLimits);
if (cmpPlayerEntityLimits)
{
if (!cmpPlayerEntityLimits.AllowedToTrain(unitCategory, this.count, this.templateName, template.TrainingRestrictions.MatchLimit))
// Already warned, return.
{
cmpPlayer.RefundResources(totalResources);
return false;
}
// ToDo: Should warn here v and return?
cmpPlayerEntityLimits.ChangeCount(unitCategory, this.count);
if (template.TrainingRestrictions.MatchLimit)
cmpPlayerEntityLimits.ChangeMatchCount(this.templateName, this.count);
}
}
const buildTime = ApplyValueModificationsToTemplate("Cost/BuildTime", +template.Cost.BuildTime, this.player, template);
const time = batchTimeMultiplier * (trainCostMultiplier.time || 1) * buildTime * 1000;
this.timeRemaining = time;
this.timeTotal = time;
const cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
cmpTrigger.CallEvent("OnTrainingQueued", {
"playerid": this.player,
"unitTemplate": this.templateName,
"count": this.count,
"metadata": this.metadata,
"trainerEntity": this.trainer
});
return true;
};
/**
* Destroy cached entities, refund resources and free (population) limits.
*/
Trainer.prototype.Item.prototype.Stop = function()
{
// Destroy any cached entities (those which didn't spawn for some reason).
if (this.entities?.length)
{
for (const ent of this.entities)
Engine.DestroyEntity(ent);
delete this.entities;
}
const cmpPlayer = QueryPlayerIDInterface(this.player);
const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
const template = cmpTemplateManager.GetTemplate(this.templateName);
if (template.TrainingRestrictions)
{
const cmpPlayerEntityLimits = QueryPlayerIDInterface(this.player, IID_EntityLimits);
if (cmpPlayerEntityLimits)
cmpPlayerEntityLimits.ChangeCount(template.TrainingRestrictions.Category, -this.count);
if (template.TrainingRestrictions.MatchLimit)
cmpPlayerEntityLimits.ChangeMatchCount(this.templateName, -this.count);
}
const cmpStatisticsTracker = QueryPlayerIDInterface(this.player, IID_StatisticsTracker);
const totalCosts = {};
for (const resource in this.resources)
{
totalCosts[resource] = Math.floor(this.count * this.resources[resource]);
if (cmpStatisticsTracker)
cmpStatisticsTracker.IncreaseResourceUsedCounter(resource, -totalCosts[resource]);
}
if (cmpPlayer)
{
if (this.started)
cmpPlayer.UnReservePopulationSlots(this.population * this.count);
cmpPlayer.RefundResources(totalCosts);
cmpPlayer.UnBlockTraining();
}
delete this.resources;
};
/**
* This starts the item, reserving population.
* @return {boolean} - Whether the item was started successfully.
*/
Trainer.prototype.Item.prototype.Start = function()
{
const cmpPlayer = QueryPlayerIDInterface(this.player);
if (!cmpPlayer)
return false;
const template = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager).GetTemplate(this.templateName);
this.population = ApplyValueModificationsToTemplate(
"Cost/Population",
+template.Cost.Population,
this.player,
template);
this.missingPopSpace = cmpPlayer.TryReservePopulationSlots(this.population * this.count);
if (this.missingPopSpace)
{
cmpPlayer.BlockTraining();
return false;
}
cmpPlayer.UnBlockTraining();
Engine.PostMessage(this.trainer, MT_TrainingStarted, { "entity": this.trainer });
this.started = true;
return true;
};
Trainer.prototype.Item.prototype.Finish = function()
{
this.Spawn();
if (!this.count)
this.finished = true;
};
/*
* This function creates the entities and places them in world if possible
* (some of these entities may be garrisoned directly if autogarrison, the others are spawned).
*/
Trainer.prototype.Item.prototype.Spawn = function()
{
const createdEnts = [];
const spawnedEnts = [];
// We need entities to test spawning, but we don't want to waste resources,
// so only create them once and use as needed.
if (!this.entities)
{
this.entities = [];
for (let i = 0; i < this.count; ++i)
this.entities.push(Engine.AddEntity(this.templateName));
}
let autoGarrison;
const cmpRallyPoint = Engine.QueryInterface(this.trainer, IID_RallyPoint);
if (cmpRallyPoint)
{
const data = cmpRallyPoint.GetData()[0];
if (data?.target && data.target == this.trainer && data.command == "garrison")
autoGarrison = true;
}
const cmpFootprint = Engine.QueryInterface(this.trainer, IID_Footprint);
const cmpPosition = Engine.QueryInterface(this.trainer, IID_Position);
const positionTrainer = cmpPosition && cmpPosition.GetPosition();
const cmpPlayerEntityLimits = QueryPlayerIDInterface(this.player, IID_EntityLimits);
const cmpPlayerStatisticsTracker = QueryPlayerIDInterface(this.player, IID_StatisticsTracker);
while (this.entities.length)
{
const ent = this.entities[0];
const cmpNewOwnership = Engine.QueryInterface(ent, IID_Ownership);
let garrisoned = false;
if (autoGarrison)
{
const cmpGarrisonable = Engine.QueryInterface(ent, IID_Garrisonable);
if (cmpGarrisonable)
{
// Temporary owner affectation needed for GarrisonHolder checks.
cmpNewOwnership.SetOwnerQuiet(this.player);
garrisoned = cmpGarrisonable.Garrison(this.trainer);
cmpNewOwnership.SetOwnerQuiet(INVALID_PLAYER);
}
}
if (!garrisoned)
{
const pos = cmpFootprint.PickSpawnPoint(ent);
if (pos.y < 0)
break;
const cmpNewPosition = Engine.QueryInterface(ent, IID_Position);
cmpNewPosition.JumpTo(pos.x, pos.z);
if (positionTrainer)
cmpNewPosition.SetYRotation(positionTrainer.horizAngleTo(pos));
spawnedEnts.push(ent);
}
// Decrement entity count in the EntityLimits component
// since it will be increased by EntityLimits.OnGlobalOwnershipChanged,
// i.e. we replace a 'trained' entity by 'alive' one.
// Must be done after spawn check so EntityLimits decrements only if unit spawns.
if (cmpPlayerEntityLimits)
{
const cmpTrainingRestrictions = Engine.QueryInterface(ent, IID_TrainingRestrictions);
if (cmpTrainingRestrictions)
cmpPlayerEntityLimits.ChangeCount(cmpTrainingRestrictions.GetCategory(), -1);
}
cmpNewOwnership.SetOwner(this.player);
if (cmpPlayerStatisticsTracker)
cmpPlayerStatisticsTracker.IncreaseTrainedUnitsCounter(ent);
this.count--;
this.entities.shift();
createdEnts.push(ent);
}
if (spawnedEnts.length && !autoGarrison && cmpRallyPoint)
for (const com of GetRallyPointCommands(cmpRallyPoint, spawnedEnts))
ProcessCommand(this.player, com);
const cmpPlayer = QueryOwnerInterface(this.trainer);
if (createdEnts.length)
{
if (this.population)
cmpPlayer.UnReservePopulationSlots(this.population * createdEnts.length);
// Play a sound, but only for the first in the batch (to avoid nasty phasing effects).
PlaySound("trained", createdEnts[0]);
Engine.PostMessage(this.trainer, MT_TrainingFinished, {
"entities": createdEnts,
"owner": this.player,
"metadata": this.metadata
});
}
if (this.count)
{
cmpPlayer.BlockTraining();
if (!this.spawnNotified)
{
Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).PushNotification({
"players": [cmpPlayer.GetPlayerID()],
"message": markForTranslation("Can't find free space to spawn trained units."),
"translateMessage": true
});
this.spawnNotified = true;
}
}
else
{
cmpPlayer.UnBlockTraining();
delete this.spawnNotified;
}
};
/**
* @param {number} allocatedTime - The time allocated to this item.
* @return {number} - The time used for this item.
*/
Trainer.prototype.Item.prototype.Progress = function(allocatedTime)
{
// We couldn't start this timeout, try again later.
if (!this.started && !this.Start())
return allocatedTime;
if (this.timeRemaining > allocatedTime)
{
this.timeRemaining -= allocatedTime;
return allocatedTime;
}
this.Finish();
return this.timeRemaining;
};
Trainer.prototype.Item.prototype.Pause = function()
{
this.paused = true;
};
Trainer.prototype.Item.prototype.Unpause = function()
{
delete this.paused;
};
/**
* @return {Object} - Some basic information of this batch.
*/
Trainer.prototype.Item.prototype.GetBasicInfo = function()
{
return {
"unitTemplate": this.templateName,
"count": this.count,
"neededSlots": this.missingPopSpace,
"progress": 1 - (this.timeRemaining / this.timeTotal),
"timeRemaining": this.timeRemaining,
"paused": this.paused,
"metadata": this.metadata
};
};
Trainer.prototype.Item.prototype.Serialize = function(id)
{
return {
"id": id,
"count": this.count,
"entities": this.entities,
"metadata": this.metadata,
"missingPopSpace": this.missingPopSpace,
"paused": this.paused,
"player": this.player,
+ "population": this.population,
"trainer": this.trainer,
"resource": this.resources,
"started": this.started,
"templateName": this.templateName,
"timeRemaining": this.timeRemaining,
"timeTotal": this.timeTotal,
};
};
Trainer.prototype.Item.prototype.Deserialize = function(data)
{
this.Init(data.templateName, data.count, data.trainer, data.metadata);
this.entities = data.entities;
this.missingPopSpace = data.missingPopSpace;
this.paused = data.paused;
this.player = data.player;
+ this.population = data.population;
this.trainer = data.trainer;
this.resources = data.resources;
this.started = data.started;
this.timeRemaining = data.timeRemaining;
this.timeTotal = data.timeTotal;
};
Trainer.prototype.Init = function()
{
this.nextID = 1;
this.queue = new Map();
};
Trainer.prototype.Serialize = function()
{
const queue = [];
for (const [id, item] of this.queue)
queue.push(item.Serialize(id));
return {
"entitiesMap": this.entitiesMap,
"nextID": this.nextID,
"queue": queue
};
};
Trainer.prototype.Deserialize = function(data)
{
this.Init();
this.entitiesMap = data.entitiesMap;
this.nextID = data.nextID;
for (const item of data.queue)
{
const newItem = new this.Item();
newItem.Deserialize(item);
this.queue.set(item.id, newItem);
}
};
/*
* Returns list of entities that can be trained by this entity.
*/
Trainer.prototype.GetEntitiesList = function()
{
return Array.from(this.entitiesMap.values());
};
/**
* Calculate the new list of producible entities
* and update any entities currently being produced.
*/
Trainer.prototype.CalculateEntitiesMap = function()
{
// Don't reset the map, it's used below to update entities.
if (!this.entitiesMap)
this.entitiesMap = new Map();
if (!this.template.Entities)
return;
const string = this.template.Entities._string;
// Tokens can be added -> process an empty list to get them.
let addedTokens = ApplyValueModificationsToEntity("Trainer/Entities/_string", "", this.entity);
if (!addedTokens && !string)
return;
addedTokens = addedTokens == "" ? [] : addedTokens.split(/\s+/);
const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
const cmpPlayer = QueryOwnerInterface(this.entity);
const disabledEntities = cmpPlayer ? cmpPlayer.GetDisabledTemplates() : {};
/**
* Process tokens:
* - process token modifiers (this is a bit tricky).
* - replace the "{civ}" and "{native}" codes with the owner's civ ID and entity's civ ID
* - remove disabled entities
* - upgrade templates where necessary
* This also updates currently queued production (it's more convenient to do it here).
*/
const removeAllQueuedTemplate = (token) => {
const queue = clone(this.queue);
const template = this.entitiesMap.get(token);
for (const [id, item] of queue)
if (item.templateName == template)
this.StopBatch(id);
};
// ToDo: Notice this doesn't account for entity limits changing due to the template change.
const updateAllQueuedTemplate = (token, updateTo) => {
const template = this.entitiesMap.get(token);
for (const [id, item] of this.queue)
if (item.templateName === template)
item.templateName = updateTo;
};
const toks = string.split(/\s+/);
for (const tok of addedTokens)
toks.push(tok);
const nativeCiv = Engine.QueryInterface(this.entity, IID_Identity)?.GetCiv();
const playerCiv = cmpPlayer?.GetCiv();
const addedDict = addedTokens.reduce((out, token) => { out[token] = true; return out; }, {});
this.entitiesMap = toks.reduce((entMap, token) => {
const rawToken = token;
if (!(token in addedDict))
{
// This is a bit wasteful but I can't think of a simpler/better way.
// The list of token is unlikely to be a performance bottleneck anyways.
token = ApplyValueModificationsToEntity("Trainer/Entities/_string", token, this.entity);
token = token.split(/\s+/);
if (token.every(tok => addedTokens.indexOf(tok) !== -1))
{
removeAllQueuedTemplate(rawToken);
return entMap;
}
token = token[0];
}
// Replace the "{civ}" and "{native}" codes with the owner's civ ID and entity's civ ID.
if (nativeCiv)
token = token.replace(/\{native\}/g, nativeCiv);
if (playerCiv)
token = token.replace(/\{civ\}/g, playerCiv);
// Filter out disabled and invalid entities.
if (disabledEntities[token] || !cmpTemplateManager.TemplateExists(token))
{
removeAllQueuedTemplate(rawToken);
return entMap;
}
token = this.GetUpgradedTemplate(token);
entMap.set(rawToken, token);
updateAllQueuedTemplate(rawToken, token);
return entMap;
}, new Map());
};
/*
* Returns the upgraded template name if necessary.
*/
Trainer.prototype.GetUpgradedTemplate = function(templateName)
{
const cmpPlayer = QueryOwnerInterface(this.entity);
if (!cmpPlayer)
return templateName;
const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
let template = cmpTemplateManager.GetTemplate(templateName);
while (template && template.Promotion !== undefined)
{
const requiredXp = ApplyValueModificationsToTemplate(
"Promotion/RequiredXp",
+template.Promotion.RequiredXp,
cmpPlayer.GetPlayerID(),
template);
if (requiredXp > 0)
break;
templateName = template.Promotion.Entity;
template = cmpTemplateManager.GetTemplate(templateName);
}
return templateName;
};
/**
* @return {Object} - The multipliers to change the costs of any training activity with.
*/
Trainer.prototype.GetTrainCostMultiplier = function()
{
const trainCostMultiplier = {};
for (const res in this.template.TrainCostMultiplier)
trainCostMultiplier[res] = ApplyValueModificationsToEntity(
"Trainer/TrainCostMultiplier/" + res,
+this.template.TrainCostMultiplier[res],
this.entity);
return trainCostMultiplier;
};
/*
* Returns batch build time.
*/
Trainer.prototype.GetBatchTime = function(batchSize)
{
// TODO: work out what equation we should use here.
return Math.pow(batchSize, ApplyValueModificationsToEntity(
"Trainer/BatchTimeModifier",
+(this.template.BatchTimeModifier || 1),
this.entity));
};
/**
* @param {string} templateName - The template name to check.
* @return {boolean} - Whether we can train this template.
*/
Trainer.prototype.CanTrain = function(templateName)
{
return this.GetEntitiesList().includes(templateName);
};
/**
* @param {string} templateName - The entity to queue.
* @param {number} count - The batch size.
* @param {string} metadata - Any metadata attached to the item.
*
* @return {number} - The ID of the item. -1 if the item could not be queued.
*/
Trainer.prototype.QueueBatch = function(templateName, count, metadata)
{
const item = new this.Item();
item.Init(templateName, count, this.entity, metadata);
const trainCostMultiplier = this.GetTrainCostMultiplier();
const batchTimeMultiplier = this.GetBatchTime(count);
if (!item.Queue(trainCostMultiplier, batchTimeMultiplier))
return -1;
const id = this.nextID++;
this.queue.set(id, item);
return id;
};
/**
* @param {number} id - The ID of the batch being trained here we need to stop.
*/
Trainer.prototype.StopBatch = function(id)
{
this.queue.get(id).Stop();
this.queue.delete(id);
};
/**
* @param {number} id - The ID of the training.
*/
Trainer.prototype.PauseBatch = function(id)
{
this.queue.get(id).Pause();
};
/**
* @param {number} id - The ID of the training.
*/
Trainer.prototype.UnpauseBatch = function(id)
{
this.queue.get(id).Unpause();
};
/**
* @param {number} id - The ID of the batch to check.
* @return {boolean} - Whether we are currently training the batch.
*/
Trainer.prototype.HasBatch = function(id)
{
return this.queue.has(id);
};
/**
* @parameter {number} id - The id of the training.
* @return {Object} - Some basic information about the training.
*/
Trainer.prototype.GetBatch = function(id)
{
const item = this.queue.get(id);
return item?.GetBasicInfo();
};
/**
* @param {number} id - The ID of the item we spent time on.
* @param {number} allocatedTime - The time we spent on the given item.
* @return {number} - The time we've actually used.
*/
Trainer.prototype.Progress = function(id, allocatedTime)
{
const item = this.queue.get(id);
const usedTime = item.Progress(allocatedTime);
if (item.finished)
this.queue.delete(id);
return usedTime;
};
Trainer.prototype.OnCivChanged = function()
{
this.CalculateEntitiesMap();
};
Trainer.prototype.OnOwnershipChanged = function(msg)
{
if (msg.to != INVALID_PLAYER)
this.CalculateEntitiesMap();
};
Trainer.prototype.OnValueModification = function(msg)
{
// If the promotion requirements of units is changed,
// update the entities list so that automatically promoted units are shown
// appropriately in the list.
if (msg.component != "Promotion" && (msg.component != "Trainer" ||
!msg.valueNames.some(val => val.startsWith("Trainer/Entities/"))))
return;
if (msg.entities.indexOf(this.entity) === -1)
return;
// This also updates the queued production if necessary.
this.CalculateEntitiesMap();
// Inform the GUI that it'll need to recompute the selection panel.
// TODO: it would be better to only send the message if something actually changing
// for the current training queue.
const cmpPlayer = QueryOwnerInterface(this.entity);
if (cmpPlayer)
Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).SetSelectionDirty(cmpPlayer.GetPlayerID());
};
Trainer.prototype.OnDisabledTemplatesChanged = function(msg)
{
this.CalculateEntitiesMap();
};
Engine.RegisterComponentType(IID_Trainer, "Trainer", Trainer);
Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/athen/gymnasium.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/structures/athen/gymnasium.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/athen/gymnasium.xml (revision 26015)
@@ -1,56 +1,57 @@
200
200
200
8.0
10
2000
athen
Gymnasium
Gymnasion
Train Champions.
ConquestCritical CivSpecific
Gymnasium
structures/gymnasium.png
40
40
+
interface/complete/building/complete_gymnasium.xml
0.7
units/{civ}/champion_infantry
units/{civ}/champion_ranged
40
structures/athenians/gymnasium.xml
structures/fndn_8x9.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/athen/prytaneion.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/structures/athen/prytaneion.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/athen/prytaneion.xml (revision 26015)
@@ -1,67 +1,68 @@
Council
200
100
200
8.0
2000
athen
Council Chamber
Prytaneion
Train Heroes and research technologies.
ConquestCritical CivSpecific
Council
structures/tholos.png
20
40
+
long_walls
iphicratean_reforms
interface/complete/building/complete_tholos.xml
false
38
40000
0.7
units/{civ}/hero_themistocles
units/{civ}/hero_pericles
units/{civ}/hero_iphicrates
40
structures/athenians/prytaneion.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/assembly.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/assembly.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/assembly.xml (revision 26015)
@@ -1,77 +1,78 @@
200
400
10.0
20
0.1
Unit
Support Infantry Cavalry
0
2
2000
decay|rubble/rubble_stone_6x6
gaul
Assembly of Princes
Remogantion
Train Champion Trumpeters and Heroes.
ConquestCritical CivSpecific
City Council
structures/tholos.png
phase_city
80
+
20
30
3
interface/complete/building/complete_iber_monument.xml
false
40
40000
0.7
units/{civ}/champion_infantry_trumpeter
units/{civ}/hero_brennus
units/{civ}/hero_viridomarus
units/{civ}/hero_vercingetorix
40
structures/gauls/theater.xml
structures/fndn_6x6.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/pers/apadana.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/structures/pers/apadana.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/pers/apadana.xml (revision 26015)
@@ -1,81 +1,82 @@
Palace
300
300
200
8.0
10
3000
decay|rubble/rubble_stone_6x6
pers
Throne Hall
Apadāna
Train Champions and Heroes.
ConquestCritical CivSpecific
Palace
structures/palace.png
60
40
+
immortals
1.0
1.0
0.75
0.75
2000
interface/complete/building/complete_broch.xml
true
48
40000
0.8
units/{civ}/champion_infantry
units/{civ}/hero_cyrus_ii
units/{civ}/hero_darius_i
units/{civ}/hero_xerxes_i
40
structures/persians/apadana.xml
structures/fndn_8x9.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/rome/army_camp.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/structures/rome/army_camp.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/rome/army_camp.xml (revision 26015)
@@ -1,127 +1,128 @@
Bow
10
60
1200
2000
100
1.5
50
false
Human
outline_border.png
outline_border_mask.png
0.175
neutral enemy
ArmyCamp
ArmyCamp
80
3
15
1
Soldier
3
10.0
3.0
250
500
100
100
12.0
20
0.1
Unit
Support Infantry Cavalry Siege
0
6
2250
decay|rubble/rubble_rome_sb
rome
Army Camp
Castra
Build in neutral or enemy territory. Train Advanced Melee Infantry. Construct Rams. Garrison Soldiers for additional arrows.
ConquestCritical CivSpecific
City ArmyCamp
structures/roman_camp.png
phase_city
100
+
15
35
3
interface/complete/building/complete_broch.xml
attack/weapon/bow_attack.xml
attack/impact/arrow_impact.xml
2
0.7
units/{civ}/infantry_axeman_a
units/{civ}/infantry_swordsman_a
units/{civ}/infantry_spearman_a
units/{civ}/infantry_pikeman_a
units/{civ}/siege_ram
90
structures/romans/camp.xml
structures/fndn_8x8.xml
29.5
8
Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/spart/gerousia.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/structures/spart/gerousia.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/spart/gerousia.xml (revision 26015)
@@ -1,59 +1,60 @@
Council
200
100
200
8.0
2000
spart
Spartan Senate
Gerousia
Train Heroes.
ConquestCritical
Council
structures/tholos.png
20
40
+
interface/complete/building/complete_tholos.xml
false
38
40000
0.7
units/{civ}/hero_leonidas
40
structures/spartans/gerousia.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/spart/syssiton.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/structures/spart/syssiton.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/spart/syssiton.xml (revision 26015)
@@ -1,69 +1,70 @@
200
200
200
8.0
10
2000
decay|rubble/rubble_stone_4x6
spart
Military Mess Hall
Syssition
Train Champions and Heroes.
ConquestCritical CivSpecific
Syssiton
structures/syssition.png
40
40
+
agoge
interface/complete/building/complete_gymnasium.xml
false
38
40000
0.7
units/{civ}/champion_infantry_spear
units/{civ}/hero_leonidas
units/{civ}/hero_brasidas
units/{civ}/hero_agis
40
structures/spartans/syssiton.xml
structures/fndn_5x8.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure.xml (revision 26015)
@@ -1,185 +1,172 @@
land
own
Structure
500
0.5
5.0
0
10
0
0
0
0
false
false
0.0
3.0
9.8
0.85
0.65
0.35
corpse
0
0
true
gaia
Structure
Structure
false
0
0
0
0
0
structure
true
true
true
true
false
false
false
false
0
upright
false
0
6
-
special/rallypoint
art/textures/misc/rallypoint_line.png
art/textures/misc/rallypoint_line_mask.png
0.25
square
round
default
2.0
-
-
- 1.0
- 1.0
- 1.0
- 1.0
-
-
-
0.0
1
1
10
1
0.0
1
1
10
1
outline_border.png
outline_border_mask.png
0.4
interface/complete/building/complete_universal.xml
attack/destruction/building_collapse_large.xml
interface/alarm/alarm_attackplayer.xml
interface/alarm/alarm_attacked_gaia.xml
interface/alarm/alarm_attackplayer.xml
interface/alarm/alarm_attacked_gaia.xml
6.0
0.6
12.0
20
neutral enemy
-
- 1.0
-
true
false
false
false
4
false
false
true
false
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml (revision 26015)
@@ -1,145 +1,146 @@
FemaleCitizen
120
180
100
Bow
10
60
1200
2000
100
1.5
50
false
Human
outline_border.png
outline_border_mask.png
0.175
own neutral
CivilCentre
CivilCentre
200
3
1
Soldier
2500
5.0
500
500
500
500
8.0
20
0.1
Unit
Support Infantry Cavalry
1
1
3000
decay|rubble/rubble_stone_6x6
Civic Center
template_structure_civic_civil_centre
Build in own or neutral territory. Acquire large tracts of territory. Territory root. Train Citizens and research technologies. Garrison Soldiers for additional arrows.
CivCentre
Defensive CivilCentre
structures/civic_centre.png
100
100
100
20
+
phase_town_{civ}
phase_city_{civ}
unlock_shared_los
unlock_shared_dropsites
unlock_spies
spy_counter
archery_tradition
hoplite_tradition
hellenistic_metropolis
5
5
food wood stone metal
true
interface/complete/building/complete_civ_center.xml
interface/alarm/alarm_alert_0.xml
interface/alarm/alarm_alert_1.xml
attack/weapon/bow_attack.xml
attack/impact/arrow_impact.xml
true
140
10000
0.8
units/{civ}/support_female_citizen
90
structures/fndn_8x8.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml (revision 26015)
@@ -1,74 +1,75 @@
30
75
5.0
3
0
0.1
Unit
Support+!Elephant
1
800
decay|rubble/rubble_stone_2x2
House
template_structure_civic_house
Village House
structures/house.png
phase_village
15
5
+
health_females_01
pop_house_01
pop_house_02
unlock_females_house
interface/complete/building/complete_house.xml
8.0
false
16
65535
units/{civ}/support_female_citizen_house
20
structures/fndn_3x3.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_temple.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_temple.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_temple.xml (revision 26015)
@@ -1,75 +1,76 @@
structures/temple_heal
200
300
12.0
20
0.1
Unit
Support Infantry Cavalry
3
2
2000
decay|rubble/rubble_stone_4x6
Temple
template_structure_civic_temple
Train Healers and research healing technologies.
Town Temple
structures/temple.png
phase_town
60
+
heal_range
heal_range_2
heal_rate
heal_rate_2
garrison_heal
health_regen_units
interface/complete/building/complete_temple.xml
false
40
30000
0.8
units/{civ}/support_healer_b
40
structures/fndn_4x6.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_outpost.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_outpost.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_outpost.xml (revision 26015)
@@ -1,81 +1,82 @@
structures/wall_garrisoned
own neutral
Outpost
50
30
60
13.0
400
decay|rubble/rubble_stone_2x2
Outpost
template_structure_defensive_outpost
Build in own or neutral territory.
Outpost
structures/outpost.png
12
+
outpost_vision
10
20
1
interface/complete/building/complete_tower.xml
14.0
enemy
0
8
0
90
structures/fndn_2x2.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_palisade.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_palisade.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_palisade.xml (revision 26015)
@@ -1,38 +1,35 @@
land-shore
own neutral
Wall
1000
decay|rubble/rubble_stone_2x2
Palisade
template_structure_defensive_palisade
Wall off an area. Build in own or neutral territory.
Palisade
gaia/special_palisade.png
-
-
4
25
2
interface/complete/building/complete_wall.xml
-
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_artillery.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_artillery.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_artillery.xml (revision 26015)
@@ -1,79 +1,80 @@
Stone
90
0
80
40
15
4500
5000
40
6
9.81
false
props/units/weapons/tower_artillery_projectile.xml
props/units/weapons/tower_artillery_projectile_impact.xml
0.3
-Human !Organic
1
0
200
200
200
15.0
5
1400
Artillery Tower
template_structure_defensive_tower_artillery
ArtilleryTower
structures/tower_artillery.png
phase_city
40
40
+
tower_health
attack/impact/siegeprojectilehit.xml
attack/siege/ballist_attack.xml
false
32
30000
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_bolt.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_bolt.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_bolt.xml (revision 26015)
@@ -1,76 +1,77 @@
Bolt
100
90
30
15
500
4000
150
1
9.81
false
props/units/weapons/tower_artillery_projectile_impact.xml
0.1
1
0
200
200
100
15.0
5
1400
Bolt Tower
template_structure_defensive_tower_bolt
BoltTower
structures/tower_bolt.png
phase_city
40
20
+
tower_health
attack/weapon/arrowfly.xml
attack/impact/arrow_metal.xml
false
32
30000
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_sentry.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_sentry.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_sentry.xml (revision 26015)
@@ -1,64 +1,65 @@
9
3
40
100
9.0
3
400
Sentry Tower
template_structure_defensive_tower_sentry
Garrison Infantry for additional arrows. Needs the “Murder Holes” technology to protect its foot.
SentryTower
structures/sentry_tower.png
phase_village
20
+
tower_watch
false
16
30000
structures/{civ}/defense_tower
Reinforce with stone and upgrade to a defense tower.
phase_town
50
100
upgrading
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_stone.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_stone.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_stone.xml (revision 26015)
@@ -1,54 +1,55 @@
15
150
100
100
15.0
5
1000
Stone Tower
template_structure_defensive_tower_stone
Garrison Infantry for additional arrows. Needs the “Murder Holes” technology to protect its foot.
StoneTower
structures/defense_tower.png
phase_town
20
20
+
tower_watch
tower_crenellations
tower_range
tower_murderholes
tower_health
false
32
30000
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_wall.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_wall.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_wall.xml (revision 26015)
@@ -1,39 +1,36 @@
land-shore
Wall
8.0
Wall
template_structure_defensive_wall
Wall off your town for a stout defense.
Wall
structures/wall.png
phase_town
-
4.5
-
interface/complete/building/complete_wall.xml
false
20
65535
-
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml (revision 26015)
@@ -1,70 +1,71 @@
FemaleCitizen
50
100
100
300
45
100
8.0
900
decay|rubble/rubble_stone_4x4
Farmstead
template_structure_economic_farmstead
Research food gathering technologies.
DropsiteFood
Village Farmstead
structures/farmstead.png
phase_village
20
+
gather_wicker_baskets
gather_farming_plows
gather_farming_training
gather_farming_fertilizer
gather_farming_harvester
food
true
interface/complete/building/complete_farmstead.xml
interface/alarm/alarm_alert_0.xml
interface/alarm/alarm_alert_1.xml
false
20
30000
20
structures/fndn_5x5.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml (revision 26015)
@@ -1,75 +1,76 @@
Trader+!Ship
-1
-1
100
150
300
8.0
1500
decay|rubble/rubble_stone_5x5
Market
template_structure_economic_market
Barter resources. Establish trade routes. Train Traders and research trade and barter technologies.
Barter
Trade Town Market
structures/market.png
phase_town
60
land
0.2
+
trader_health
trade_gain_01
trade_gain_02
trade_commercial_treaty
interface/complete/building/complete_market.xml
interface/alarm/alarm_alert_0.xml
interface/alarm/alarm_alert_1.xml
false
40
30000
0.7
units/{civ}/support_trader
32
structures/fndn_8x8.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml (revision 26015)
@@ -1,78 +1,79 @@
FemaleCitizen
50
100
100
40
100
8.0
800
decay|rubble/rubble_stone_3x3
Storehouse
template_structure_economic_storehouse
Research gathering technologies.
DropsiteWood DropsiteMetal DropsiteStone
Village Storehouse
structures/storehouse.png
phase_village
20
+
gather_lumbering_ironaxes
gather_lumbering_strongeraxes
gather_lumbering_sharpaxes
gather_mining_servants
gather_mining_serfs
gather_mining_slaves
gather_mining_wedgemallet
gather_mining_shaftmining
gather_mining_silvermining
gather_capacity_basket
gather_capacity_wheelbarrow
gather_capacity_carts
wood stone metal
true
interface/complete/building/complete_storehouse.xml
interface/alarm/alarm_alert_0.xml
interface/alarm/alarm_alert_1.xml
false
20
30000
20
structures/fndn_3x3.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_arsenal.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_arsenal.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_arsenal.xml (revision 26015)
@@ -1,75 +1,76 @@
structures/arsenal_repair
180
300
12.0
2
Siege
2000
decay|rubble/rubble_stone_5x5
Arsenal
template_structure_military_arsenal
Train Champion Infantry Crossbowmen, construct Siege Engines, and research Siege Engine technologies.
City Arsenal
structures/siege_workshop.png
phase_city
60
+
siege_attack
siege_cost_time
siege_health
siege_pack_unpack
siege_bolt_accuracy
interface/complete/building/complete_barracks.xml
38
0.7
units/{civ}/champion_infantry_crossbowman
units/{civ}/siege_scorpio_packed
units/{civ}/siege_polybolos_packed
units/{civ}/siege_oxybeles_packed
units/{civ}/siege_lithobolos_packed
units/{civ}/siege_ballista_packed
units/{civ}/siege_ram
units/{civ}/siege_tower
40
structures/fndn_8x8.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml (revision 26015)
@@ -1,86 +1,87 @@
own ally neutral
shore
Dock
150
200
8.0
2500
decay|rubble/rubble_stone_4x4
Dock
template_structure_military_dock
Build upon a shoreline in own, neutral, or allied territory. Establish trade routes. Construct Ships and research Ship technologies.
Economic Naval Trade Village Dock
structures/dock.png
40
land naval
0.2
true
0.0
+
ship
fishing_boat_gather_rate
fishing_boat_gather_capacity
ship_cost_time
ship_health
ship_movement_speed
equine_transports
food wood stone metal
true
interface/complete/building/complete_dock.xml
0.8
units/{civ}/ship_fishing
units/{civ}/ship_merchant
units/{civ}/ship_bireme
units/{civ}/ship_trireme
units/{civ}/ship_quinquereme
units/{civ}/ship_fire
40
structures/fndn_4x4_dock.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_embassy.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_embassy.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_embassy.xml (revision 26015)
@@ -1,55 +1,56 @@
Embassy
150
12.0
6
Support Infantry Cavalry
2000
decay|rubble/rubble_stone_3x3
Embassy
template_structure_military_embassy
Town Embassy
phase_town
+
30
interface/complete/building/complete_gymnasium.xml
25
0.8
24
structures/fndn_4x4.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml (revision 26015)
@@ -1,108 +1,109 @@
Bow
10
60
1200
2000
100
1.5
50
false
Human
outline_border.png
outline_border_mask.png
0.175
Fortress
Fortress
80
4
1
Soldier
8
10.0
450
300
600
8.0
20
0.075
Support Infantry Cavalry Siege
6
5200
decay|rubble/rubble_stone_6x6
Fortress
template_structure_military_fortress
Garrison Soldiers for additional arrows.
GarrisonFortress
Defensive Fortress
structures/fortress.png
phase_city
60
120
+
attack_soldiers_will
interface/complete/building/complete_fortress.xml
attack/weapon/bow_attack.xml
attack/impact/arrow_impact.xml
2
80
0.8
90
structures/fndn_8x8.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_stable.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_stable.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_stable.xml (revision 26015)
@@ -1,73 +1,74 @@
structures/xp_trickle
120
200
50
12.0
10
Cavalry
2000
decay|rubble/rubble_stone_5x5
Stable
template_structure_military_stable
Train Cavalry and research Cavalry technologies.
Village Stable
structures/stable.png
phase_village
40
10
+
stable_batch_training
cavalry_cost_time
cavalry_movement_speed
cavalry_health
nisean_horses
unlock_champion_cavalry
unlock_champion_chariots
interface/complete/building/complete_stable.xml
0.8
units/{civ}/cavalry_axeman_b
units/{civ}/cavalry_swordsman_b
units/{civ}/cavalry_spearman_b
units/{civ}/cavalry_javelineer_b
units/{civ}/cavalry_archer_b
units/{civ}/champion_cavalry
units/{civ}/champion_chariot
units/{civ}/war_dog
32
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special_amphitheater.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special_amphitheater.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special_amphitheater.xml (revision 26015)
@@ -1,54 +1,55 @@
500
500
500
20.0
2000
Amphitheater
template_structure_special_amphitheater
Amphitheater
structures/theater.png
100
100
+
interface/complete/building/complete_tholos.xml
false
100
40000
0.8
units/{civ}/champion_infantry_spear_gladiator
units/{civ}/champion_infantry_sword_gladiator
40
structures/fndn_6x6.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special_theater.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special_theater.xml (revision 26014)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special_theater.xml (revision 26015)
@@ -1,55 +1,52 @@
structures/theater
Theater
500
200
600
200
10.0
3000
Theater
template_structure_special_theater
Theater
structures/theater.png
40
120
40
-
-
interface/complete/building/complete_greek_theater.xml
false
100
40000
-
40