2012-04-20 19:21:04 +02:00
var g _ProgressInterval = 1000 ;
const MAX _QUEUE _SIZE = 16 ;
function ProductionQueue ( ) { }
ProductionQueue . prototype . Schema =
"<a:help>Allows the building to train new units and research technologies</a:help>" +
"<a:example>" +
2012-11-25 17:23:59 +01:00
"<BatchTimeModifier>0.7</BatchTimeModifier>" +
2012-04-20 19:21:04 +02:00
"<Entities datatype='tokens'>" +
"\n units/{civ}_support_female_citizen\n units/{civ}_support_trader\n units/celt_infantry_spearman_b\n " +
"</Entities>" +
"</a:example>" +
2012-11-25 17:23:59 +01:00
"<element name='BatchTimeModifier' a:help='Modifier that influences the time benefit for batch training'>" +
2012-11-25 03:52:13 +01:00
"<ref name='nonNegativeDecimal'/>" +
"</element>" +
2012-04-20 19:21:04 +02:00
"<optional>" +
"<element name='Entities' a:help='Space-separated list of entity template names that this building can train. The special string \"{civ}\" will be automatically replaced by the building's four-character civ code'>" +
"<attribute name='datatype'>" +
"<value>tokens</value>" +
"</attribute>" +
"<text/>" +
"</element>" +
"</optional>" +
"<optional>" +
"<element name='Technologies' a:help='Space-separated list of technology names that this building can research.'>" +
"<attribute name='datatype'>" +
"<value>tokens</value>" +
"</attribute>" +
"<text/>" +
"</element>" +
"</optional>" ;
ProductionQueue . prototype . Init = function ( )
{
this . nextID = 1 ;
this . queue = [ ] ;
// Queue items are:
// {
// "id": 1,
// "player": 1, // who paid for this batch; we need this to cope with refunds cleanly
// "unitTemplate": "units/example",
// "count": 10,
2013-02-25 21:30:02 +01:00
// "neededSlots": 3, // number of population slots missing for production to begin
2012-04-20 19:21:04 +02:00
// "resources": { "wood": 100, ... }, // resources per unit, multiply by count to get total
// "population": 1, // population per unit, multiply by count to get total
// "productionStarted": false, // true iff we have reserved population
// "timeTotal": 15000, // msecs
// "timeRemaining": 10000, // msecs
// }
//
// {
// "id": 1,
// "player": 1, // who paid for this research; we need this to cope with refunds cleanly
// "technologyTemplate": "example_tech",
// "resources": { "wood": 100, ... }, // resources needed for research
// "productionStarted": false, // true iff production has started
// "timeTotal": 15000, // msecs
// "timeRemaining": 10000, // msecs
// }
this . timer = undefined ; // g_ProgressInterval msec timer, active while the queue is non-empty
2013-05-22 01:01:53 +02:00
this . paused = false ;
2012-04-20 19:21:04 +02:00
this . entityCache = [ ] ;
this . spawnNotified = false ;
} ;
/ *
* Returns list of entities that can be trained by this building .
* /
ProductionQueue . prototype . GetEntitiesList = function ( )
{
2013-12-26 02:05:35 +01:00
if ( ! this . entitiesList )
Mythos_Ruler's Christmas update for SVN users!
Includes:
- Unit rank upgrades, based on a patch by Sanderd. Not all civs get all
rank upgrades. For instance, Spartans get the Infantry rank upgrades,
but not the cavalry rank upgrades. Conversely, the Persians get the
cavalry rank upgrades, but not the infantry rank upgrades. Carthaginians
get rank upgrades for their mercenaries, but not their native units.
etc.
- Updated and tweaked many of the skirmish maps. Too many tweaks to
mention. But I did add Iberian circuit walls to many of them! New
"Bactria" Skirmish Map. Will continue to tweak this one to make it more
unique. It's based on modern-day Afghanistan, which the ancients called
"Bactria." A 2nd Ptolemies sandbox demo map.
- Moved the Ptolemaic Lighthouse to Town Phase to have more impact for
the Ptolemy player on maps with water.
- New Thureos shield patterns by Enrique for a NEW unit: Mercenary
Thureos Spearman.
- TECHNOLOGIES: Some techs renamed and tweaked. Plus, a new "Iron Armor"
tech for Heroes. A new "Roman Logistics" tech for the Roman Army Camp
and Siege Walls. A new "Battlefield Medics" tech for the temple that
unlocks (slow) health regeneration for units. The portrait for this tech
is placeholder and needs replaced ASAP.
- Cavalry now have oval selection rings. Eventually I will implement a
selection ring system where the citizen-soldiers and support units have
round rings, while champions have arrows, and heroes have stars. This
helps visually differentiate the roles of these 3 classes of units. Not
yet implemented.
- Vision radius for infantry slightly reduced.
- Fixed sounds for Persian Wonder.
- Fixed footprint sizes for a few buildings and Ptolemaic walls.
- Ptolemies now have the "Military Settlement" system in place. But this
system might go to the Seleucids instead later for historical reasons.
- Cost of fields reduced. Gathering rates for grain reduced.
- Fixed some selection group names for some templates. (Double clicking
didn't select them all as it should have).
- Fixed/Changed/Added some unit and building names, specifically for the
Ptolemies, but for some others as well.
- Some new temp portraits for Ptolemaic units. Ongoing task.
Lastly, I hope these changes don't break anything. They are heavily
tested on my end, but I can't promise I caught all bugs.
This was SVN commit r14388.
2013-12-25 16:49:49 +01:00
this . CalculateEntitiesList ( ) ;
return this . entitiesList ;
} ;
ProductionQueue . prototype . CalculateEntitiesList = function ( )
{
this . entitiesList = [ ] ;
2012-04-20 19:21:04 +02:00
if ( ! this . template . Entities )
Mythos_Ruler's Christmas update for SVN users!
Includes:
- Unit rank upgrades, based on a patch by Sanderd. Not all civs get all
rank upgrades. For instance, Spartans get the Infantry rank upgrades,
but not the cavalry rank upgrades. Conversely, the Persians get the
cavalry rank upgrades, but not the infantry rank upgrades. Carthaginians
get rank upgrades for their mercenaries, but not their native units.
etc.
- Updated and tweaked many of the skirmish maps. Too many tweaks to
mention. But I did add Iberian circuit walls to many of them! New
"Bactria" Skirmish Map. Will continue to tweak this one to make it more
unique. It's based on modern-day Afghanistan, which the ancients called
"Bactria." A 2nd Ptolemies sandbox demo map.
- Moved the Ptolemaic Lighthouse to Town Phase to have more impact for
the Ptolemy player on maps with water.
- New Thureos shield patterns by Enrique for a NEW unit: Mercenary
Thureos Spearman.
- TECHNOLOGIES: Some techs renamed and tweaked. Plus, a new "Iron Armor"
tech for Heroes. A new "Roman Logistics" tech for the Roman Army Camp
and Siege Walls. A new "Battlefield Medics" tech for the temple that
unlocks (slow) health regeneration for units. The portrait for this tech
is placeholder and needs replaced ASAP.
- Cavalry now have oval selection rings. Eventually I will implement a
selection ring system where the citizen-soldiers and support units have
round rings, while champions have arrows, and heroes have stars. This
helps visually differentiate the roles of these 3 classes of units. Not
yet implemented.
- Vision radius for infantry slightly reduced.
- Fixed sounds for Persian Wonder.
- Fixed footprint sizes for a few buildings and Ptolemaic walls.
- Ptolemies now have the "Military Settlement" system in place. But this
system might go to the Seleucids instead later for historical reasons.
- Cost of fields reduced. Gathering rates for grain reduced.
- Fixed some selection group names for some templates. (Double clicking
didn't select them all as it should have).
- Fixed/Changed/Added some unit and building names, specifically for the
Ptolemies, but for some others as well.
- Some new temp portraits for Ptolemaic units. Ongoing task.
Lastly, I hope these changes don't break anything. They are heavily
tested on my end, but I can't promise I caught all bugs.
This was SVN commit r14388.
2013-12-25 16:49:49 +01:00
return ;
2012-04-20 19:21:04 +02:00
var string = this . template . Entities . _string ;
2013-06-14 18:13:59 +02:00
if ( ! string )
Mythos_Ruler's Christmas update for SVN users!
Includes:
- Unit rank upgrades, based on a patch by Sanderd. Not all civs get all
rank upgrades. For instance, Spartans get the Infantry rank upgrades,
but not the cavalry rank upgrades. Conversely, the Persians get the
cavalry rank upgrades, but not the infantry rank upgrades. Carthaginians
get rank upgrades for their mercenaries, but not their native units.
etc.
- Updated and tweaked many of the skirmish maps. Too many tweaks to
mention. But I did add Iberian circuit walls to many of them! New
"Bactria" Skirmish Map. Will continue to tweak this one to make it more
unique. It's based on modern-day Afghanistan, which the ancients called
"Bactria." A 2nd Ptolemies sandbox demo map.
- Moved the Ptolemaic Lighthouse to Town Phase to have more impact for
the Ptolemy player on maps with water.
- New Thureos shield patterns by Enrique for a NEW unit: Mercenary
Thureos Spearman.
- TECHNOLOGIES: Some techs renamed and tweaked. Plus, a new "Iron Armor"
tech for Heroes. A new "Roman Logistics" tech for the Roman Army Camp
and Siege Walls. A new "Battlefield Medics" tech for the temple that
unlocks (slow) health regeneration for units. The portrait for this tech
is placeholder and needs replaced ASAP.
- Cavalry now have oval selection rings. Eventually I will implement a
selection ring system where the citizen-soldiers and support units have
round rings, while champions have arrows, and heroes have stars. This
helps visually differentiate the roles of these 3 classes of units. Not
yet implemented.
- Vision radius for infantry slightly reduced.
- Fixed sounds for Persian Wonder.
- Fixed footprint sizes for a few buildings and Ptolemaic walls.
- Ptolemies now have the "Military Settlement" system in place. But this
system might go to the Seleucids instead later for historical reasons.
- Cost of fields reduced. Gathering rates for grain reduced.
- Fixed some selection group names for some templates. (Double clicking
didn't select them all as it should have).
- Fixed/Changed/Added some unit and building names, specifically for the
Ptolemies, but for some others as well.
- Some new temp portraits for Ptolemaic units. Ongoing task.
Lastly, I hope these changes don't break anything. They are heavily
tested on my end, but I can't promise I caught all bugs.
This was SVN commit r14388.
2013-12-25 16:49:49 +01:00
return ;
2012-04-20 19:21:04 +02:00
// Replace the "{civ}" codes with this entity's civ ID
var cmpIdentity = Engine . QueryInterface ( this . entity , IID _Identity ) ;
if ( cmpIdentity )
string = string . replace ( /\{civ\}/g , cmpIdentity . GetCiv ( ) ) ;
Mythos_Ruler's Christmas update for SVN users!
Includes:
- Unit rank upgrades, based on a patch by Sanderd. Not all civs get all
rank upgrades. For instance, Spartans get the Infantry rank upgrades,
but not the cavalry rank upgrades. Conversely, the Persians get the
cavalry rank upgrades, but not the infantry rank upgrades. Carthaginians
get rank upgrades for their mercenaries, but not their native units.
etc.
- Updated and tweaked many of the skirmish maps. Too many tweaks to
mention. But I did add Iberian circuit walls to many of them! New
"Bactria" Skirmish Map. Will continue to tweak this one to make it more
unique. It's based on modern-day Afghanistan, which the ancients called
"Bactria." A 2nd Ptolemies sandbox demo map.
- Moved the Ptolemaic Lighthouse to Town Phase to have more impact for
the Ptolemy player on maps with water.
- New Thureos shield patterns by Enrique for a NEW unit: Mercenary
Thureos Spearman.
- TECHNOLOGIES: Some techs renamed and tweaked. Plus, a new "Iron Armor"
tech for Heroes. A new "Roman Logistics" tech for the Roman Army Camp
and Siege Walls. A new "Battlefield Medics" tech for the temple that
unlocks (slow) health regeneration for units. The portrait for this tech
is placeholder and needs replaced ASAP.
- Cavalry now have oval selection rings. Eventually I will implement a
selection ring system where the citizen-soldiers and support units have
round rings, while champions have arrows, and heroes have stars. This
helps visually differentiate the roles of these 3 classes of units. Not
yet implemented.
- Vision radius for infantry slightly reduced.
- Fixed sounds for Persian Wonder.
- Fixed footprint sizes for a few buildings and Ptolemaic walls.
- Ptolemies now have the "Military Settlement" system in place. But this
system might go to the Seleucids instead later for historical reasons.
- Cost of fields reduced. Gathering rates for grain reduced.
- Fixed some selection group names for some templates. (Double clicking
didn't select them all as it should have).
- Fixed/Changed/Added some unit and building names, specifically for the
Ptolemies, but for some others as well.
- Some new temp portraits for Ptolemaic units. Ongoing task.
Lastly, I hope these changes don't break anything. They are heavily
tested on my end, but I can't promise I caught all bugs.
This was SVN commit r14388.
2013-12-25 16:49:49 +01:00
var entitiesList = string . split ( /\s+/ ) ;
// check if some templates need to show their advanced or elite version
var cmpTemplateManager = Engine . QueryInterface ( SYSTEM _ENTITY , IID _TemplateManager ) ;
var playerID = QueryOwnerInterface ( this . entity , IID _Player ) . GetPlayerID ( ) ;
for each ( var templateName in entitiesList )
{
var template = cmpTemplateManager . GetTemplate ( templateName ) ;
while ( template . Promotion )
{
var requiredXp = ApplyValueModificationsToTemplate ( "Promotion/RequiredXp" , + template . Promotion . RequiredXp , playerID , template ) ;
if ( requiredXp > 0 )
break ;
templateName = template . Promotion . Entity ;
template = cmpTemplateManager . GetTemplate ( templateName ) ;
}
this . entitiesList . push ( templateName ) ;
}
2012-04-20 19:21:04 +02:00
} ;
/ *
* Returns list of technologies that can be researched by this building .
* /
ProductionQueue . prototype . GetTechnologiesList = function ( )
{
if ( ! this . template . Technologies )
return [ ] ;
var string = this . template . Technologies . _string ;
2013-06-14 18:13:59 +02:00
if ( ! string )
return [ ] ;
2012-04-20 19:21:04 +02:00
2012-07-20 03:54:24 +02:00
var cmpTechnologyManager = QueryOwnerInterface ( this . entity , IID _TechnologyManager ) ;
if ( ! cmpTechnologyManager )
2012-04-20 19:21:04 +02:00
return [ ] ;
var techs = string . split ( /\s+/ ) ;
2012-04-21 23:40:07 +02:00
var techList = [ ] ;
2012-04-20 19:21:04 +02:00
var superseded = { } ; // Stores the tech which supersedes the key
// Add any top level technologies to an array which corresponds to the displayed icons
// Also store what a technology is superceded by in the superceded object {"tech1":"techWhichSupercedesTech1", ...}
for ( var i in techs )
{
var tech = techs [ i ] ;
2012-07-20 03:54:24 +02:00
var template = cmpTechnologyManager . GetTechnologyTemplate ( tech ) ;
2012-04-20 19:21:04 +02:00
if ( ! template . supersedes || techs . indexOf ( template . supersedes ) === - 1 )
2012-04-21 23:40:07 +02:00
techList . push ( tech ) ;
2012-04-20 19:21:04 +02:00
else
superseded [ template . supersedes ] = tech ;
}
// Now make researched/in progress techs invisible
2012-04-21 23:40:07 +02:00
for ( var i in techList )
2012-04-20 19:21:04 +02:00
{
2012-04-21 23:40:07 +02:00
var tech = techList [ i ] ;
while ( this . IsTechnologyResearchedOrInProgress ( tech ) )
2012-04-20 19:21:04 +02:00
{
tech = superseded [ tech ] ;
}
2012-04-21 23:40:07 +02:00
techList [ i ] = tech ;
}
var ret = [ ]
2012-11-24 20:47:36 +01:00
// This inserts the techs into the correct positions to line up the technology pairs
2012-04-25 19:02:41 +02:00
for ( var i = 0 ; i < techList . length ; i ++ )
2012-04-21 23:40:07 +02:00
{
var tech = techList [ i ] ;
if ( ! tech )
{
ret [ i ] = undefined ;
continue ;
}
2012-07-20 03:54:24 +02:00
var template = cmpTechnologyManager . GetTechnologyTemplate ( tech ) ;
2012-04-21 23:40:07 +02:00
if ( template . top )
2012-04-25 19:02:41 +02:00
ret [ i ] = { "pair" : true , "top" : template . top , "bottom" : template . bottom } ;
2012-04-21 23:40:07 +02:00
else
ret [ i ] = tech ;
2012-04-20 19:21:04 +02:00
}
return ret ;
} ;
2012-04-21 23:40:07 +02:00
ProductionQueue . prototype . IsTechnologyResearchedOrInProgress = function ( tech )
{
if ( ! tech )
return false ;
2012-07-20 03:54:24 +02:00
var cmpTechnologyManager = QueryOwnerInterface ( this . entity , IID _TechnologyManager ) ;
2012-04-21 23:40:07 +02:00
2012-07-20 03:54:24 +02:00
var template = cmpTechnologyManager . GetTechnologyTemplate ( tech ) ;
2012-04-21 23:40:07 +02:00
if ( template . top )
{
2012-07-20 03:54:24 +02:00
return ( cmpTechnologyManager . IsTechnologyResearched ( template . top ) || cmpTechnologyManager . IsInProgress ( template . top )
|| cmpTechnologyManager . IsTechnologyResearched ( template . bottom ) || cmpTechnologyManager . IsInProgress ( template . bottom ) )
2012-04-21 23:40:07 +02:00
}
else
{
2012-07-20 03:54:24 +02:00
return ( cmpTechnologyManager . IsTechnologyResearched ( tech ) || cmpTechnologyManager . IsInProgress ( tech ) )
2012-04-21 23:40:07 +02:00
}
} ;
2012-04-20 19:21:04 +02:00
/ *
* Adds a new batch of identical units to train or a technology to research to the production queue .
* /
ProductionQueue . prototype . AddBatch = function ( templateName , type , count , metadata )
{
// TODO: there should probably be a limit on the number of queued batches
// 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)
var cmpPlayer = QueryOwnerInterface ( this . entity , IID _Player ) ;
if ( this . queue . length < MAX _QUEUE _SIZE )
{
if ( type == "unit" )
{
// Find the template data so we can determine the build costs
var cmpTempMan = Engine . QueryInterface ( SYSTEM _ENTITY , IID _TemplateManager ) ;
var template = cmpTempMan . GetTemplate ( templateName ) ;
if ( ! template )
return ;
Mythos_Ruler's Christmas update for SVN users!
Includes:
- Unit rank upgrades, based on a patch by Sanderd. Not all civs get all
rank upgrades. For instance, Spartans get the Infantry rank upgrades,
but not the cavalry rank upgrades. Conversely, the Persians get the
cavalry rank upgrades, but not the infantry rank upgrades. Carthaginians
get rank upgrades for their mercenaries, but not their native units.
etc.
- Updated and tweaked many of the skirmish maps. Too many tweaks to
mention. But I did add Iberian circuit walls to many of them! New
"Bactria" Skirmish Map. Will continue to tweak this one to make it more
unique. It's based on modern-day Afghanistan, which the ancients called
"Bactria." A 2nd Ptolemies sandbox demo map.
- Moved the Ptolemaic Lighthouse to Town Phase to have more impact for
the Ptolemy player on maps with water.
- New Thureos shield patterns by Enrique for a NEW unit: Mercenary
Thureos Spearman.
- TECHNOLOGIES: Some techs renamed and tweaked. Plus, a new "Iron Armor"
tech for Heroes. A new "Roman Logistics" tech for the Roman Army Camp
and Siege Walls. A new "Battlefield Medics" tech for the temple that
unlocks (slow) health regeneration for units. The portrait for this tech
is placeholder and needs replaced ASAP.
- Cavalry now have oval selection rings. Eventually I will implement a
selection ring system where the citizen-soldiers and support units have
round rings, while champions have arrows, and heroes have stars. This
helps visually differentiate the roles of these 3 classes of units. Not
yet implemented.
- Vision radius for infantry slightly reduced.
- Fixed sounds for Persian Wonder.
- Fixed footprint sizes for a few buildings and Ptolemaic walls.
- Ptolemies now have the "Military Settlement" system in place. But this
system might go to the Seleucids instead later for historical reasons.
- Cost of fields reduced. Gathering rates for grain reduced.
- Fixed some selection group names for some templates. (Double clicking
didn't select them all as it should have).
- Fixed/Changed/Added some unit and building names, specifically for the
Ptolemies, but for some others as well.
- Some new temp portraits for Ptolemaic units. Ongoing task.
Lastly, I hope these changes don't break anything. They are heavily
tested on my end, but I can't promise I caught all bugs.
This was SVN commit r14388.
2013-12-25 16:49:49 +01:00
if ( template . Promotion )
{
var requiredXp = ApplyValueModificationsToTemplate ( "Promotion/RequiredXp" , + template . Promotion . RequiredXp , cmpPlayer . GetPlayerID ( ) , template ) ;
if ( requiredXp == 0 )
{
this . AddBatch ( template . Promotion . Entity , type , count , metadata ) ;
return ;
}
}
2012-04-20 19:21:04 +02:00
// Apply a time discount to larger batches.
2012-11-24 23:04:29 +01:00
var timeMult = this . GetBatchTime ( count ) ;
2012-07-20 03:54:24 +02:00
// We need the costs after tech modifications
// Obviously we don't have the entities yet, so we must use template data
var costs = { } ;
var totalCosts = { } ;
2013-10-15 12:05:08 +02:00
var buildTime = ApplyValueModificationsToTemplate ( "Cost/BuildTime" , + template . Cost . BuildTime , cmpPlayer . GetPlayerID ( ) , template ) ;
2012-07-20 03:54:24 +02:00
var time = timeMult * buildTime ;
2012-04-20 19:21:04 +02:00
2012-07-20 03:54:24 +02:00
for ( var r in template . Cost . Resources )
{
2013-10-15 12:05:08 +02:00
costs [ r ] = ApplyValueModificationsToTemplate ( "Cost/Resources/" + r , + template . Cost . Resources [ r ] , cmpPlayer . GetPlayerID ( ) , template ) ;
2012-07-20 03:54:24 +02:00
totalCosts [ r ] = Math . floor ( count * costs [ r ] ) ;
}
2012-04-20 19:21:04 +02:00
2012-07-20 03:54:24 +02:00
var population = + template . Cost . Population ;
2012-04-20 19:21:04 +02:00
// TrySubtractResources should report error to player (they ran out of resources)
if ( ! cmpPlayer . TrySubtractResources ( totalCosts ) )
return ;
2012-11-07 18:56:14 +01:00
// Update entity count in the EntityLimits component
if ( template . TrainingRestrictions )
{
var unitCategory = template . TrainingRestrictions . Category ;
var cmpPlayerEntityLimits = QueryOwnerInterface ( this . entity , IID _EntityLimits ) ;
cmpPlayerEntityLimits . IncreaseCount ( unitCategory , count ) ;
}
2012-04-20 19:21:04 +02:00
this . queue . push ( {
"id" : this . nextID ++ ,
"player" : cmpPlayer . GetPlayerID ( ) ,
"unitTemplate" : templateName ,
"count" : count ,
"metadata" : metadata ,
2012-07-20 03:54:24 +02:00
"resources" : costs ,
2012-04-20 19:21:04 +02:00
"population" : population ,
"productionStarted" : false ,
"timeTotal" : time * 1000 ,
"timeRemaining" : time * 1000 ,
} ) ;
}
else if ( type == "technology" )
{
// Load the technology template
var cmpTechTempMan = Engine . QueryInterface ( SYSTEM _ENTITY , IID _TechnologyTemplateManager ) ;
var template = cmpTechTempMan . GetTemplate ( templateName ) ;
if ( ! template )
return ;
2012-08-05 17:24:26 +02:00
var cmpPlayer = QueryOwnerInterface ( this . entity , IID _Player ) ;
2013-07-02 01:46:03 +02:00
var time = template . researchTime * cmpPlayer . GetCheatTimeMultiplier ( ) ;
2012-04-20 19:21:04 +02:00
var cost = { } ;
for each ( var r in [ "food" , "wood" , "stone" , "metal" ] )
cost [ r ] = Math . floor ( template . cost [ r ] ) ;
// TrySubtractResources should report error to player (they ran out of resources)
if ( ! cmpPlayer . TrySubtractResources ( cost ) )
return ;
// Tell the technology manager that we have started researching this so that people can't research the same
// thing twice.
2012-07-20 03:54:24 +02:00
var cmpTechnologyManager = QueryOwnerInterface ( this . entity , IID _TechnologyManager ) ;
2012-07-31 04:03:25 +02:00
cmpTechnologyManager . QueuedResearch ( templateName , this . entity ) ;
if ( this . queue . length == 0 )
cmpTechnologyManager . StartedResearch ( templateName ) ;
2012-04-20 19:21:04 +02:00
this . queue . push ( {
"id" : this . nextID ++ ,
"player" : cmpPlayer . GetPlayerID ( ) ,
"count" : 1 ,
"technologyTemplate" : templateName ,
"resources" : deepcopy ( template . cost ) , // need to copy to avoid serialization problems
"productionStarted" : false ,
"timeTotal" : time * 1000 ,
"timeRemaining" : time * 1000 ,
} ) ;
}
else
{
warn ( "Tried to add invalid item of type \"" + type + "\" and template \"" + templateName + "\" to a production queue" ) ;
return ;
}
Engine . PostMessage ( this . entity , MT _ProductionQueueChanged , { } ) ;
// If this is the first item in the queue, start the timer
if ( ! this . timer )
{
var cmpTimer = Engine . QueryInterface ( SYSTEM _ENTITY , IID _Timer ) ;
this . timer = cmpTimer . SetTimeout ( this . entity , IID _ProductionQueue , "ProgressTimeout" , g _ProgressInterval , { } ) ;
}
}
else
{
var notification = { "player" : cmpPlayer . GetPlayerID ( ) , "message" : "The production queue is full." } ;
var cmpGUIInterface = Engine . QueryInterface ( SYSTEM _ENTITY , IID _GuiInterface ) ;
cmpGUIInterface . PushNotification ( notification ) ;
}
} ;
/ *
* Removes an existing batch of units from the production queue .
* Refunds resource costs and population reservations .
* /
ProductionQueue . prototype . RemoveBatch = function ( id )
{
// Destroy any cached entities (those which didn't spawn for some reason)
for ( var i = 0 ; i < this . entityCache . length ; ++ i )
{
Engine . DestroyEntity ( this . entityCache [ i ] ) ;
}
this . entityCache = [ ] ;
for ( var i = 0 ; i < this . queue . length ; ++ i )
{
var item = this . queue [ i ] ;
if ( item . id != id )
continue ;
// Now we've found the item to remove
var cmpPlayer = QueryPlayerIDInterface ( item . player , IID _Player ) ;
2012-11-07 18:56:14 +01:00
// Update entity count in the EntityLimits component
if ( item . unitTemplate )
{
var cmpTempMan = Engine . QueryInterface ( SYSTEM _ENTITY , IID _TemplateManager ) ;
var template = cmpTempMan . GetTemplate ( item . unitTemplate ) ;
if ( template . TrainingRestrictions )
{
var unitCategory = template . TrainingRestrictions . Category ;
2012-12-09 22:40:51 +01:00
var cmpPlayerEntityLimits = QueryPlayerIDInterface ( item . player , IID _EntityLimits ) ;
2012-11-07 18:56:14 +01:00
cmpPlayerEntityLimits . DecreaseCount ( unitCategory , item . count ) ;
}
}
2012-04-20 19:21:04 +02:00
// Refund the resource cost for this batch
var totalCosts = { } ;
2012-12-09 22:40:51 +01:00
var cmpStatisticsTracker = QueryPlayerIDInterface ( item . player , IID _StatisticsTracker ) ;
2012-04-20 19:21:04 +02:00
for each ( var r in [ "food" , "wood" , "stone" , "metal" ] )
2012-08-29 07:13:45 +02:00
{
2012-04-20 19:21:04 +02:00
totalCosts [ r ] = Math . floor ( item . count * item . resources [ r ] ) ;
2012-08-29 07:13:45 +02:00
if ( cmpStatisticsTracker )
cmpStatisticsTracker . IncreaseResourceUsedCounter ( r , - totalCosts [ r ] ) ;
}
2012-04-20 19:21:04 +02:00
cmpPlayer . AddResources ( totalCosts ) ;
// Remove reserved population slots if necessary
if ( item . productionStarted && item . unitTemplate )
cmpPlayer . UnReservePopulationSlots ( item . population * item . count ) ;
// Mark the research as stopped if we cancel it
if ( item . technologyTemplate )
{
2012-08-13 01:40:04 +02:00
// item.player is used as this.entity's owner may be invalid (deletion, etc.)
var cmpTechnologyManager = QueryPlayerIDInterface ( item . player , IID _TechnologyManager ) ;
2012-07-20 03:54:24 +02:00
cmpTechnologyManager . StoppedResearch ( item . technologyTemplate ) ;
2012-04-20 19:21:04 +02:00
}
// Remove from the queue
// (We don't need to remove the timer - it'll expire if it discovers the queue is empty)
this . queue . splice ( i , 1 ) ;
Engine . PostMessage ( this . entity , MT _ProductionQueueChanged , { } ) ;
return ;
}
} ;
/ *
* Returns basic data from all batches in the production queue .
* /
ProductionQueue . prototype . GetQueue = function ( )
{
var out = [ ] ;
for each ( var item in this . queue )
{
out . push ( {
"id" : item . id ,
"unitTemplate" : item . unitTemplate ,
"technologyTemplate" : item . technologyTemplate ,
"count" : item . count ,
2013-02-25 21:30:02 +01:00
"neededSlots" : item . neededSlots ,
2012-04-20 19:21:04 +02:00
"progress" : 1 - ( item . timeRemaining / item . timeTotal ) ,
"metadata" : item . metadata ,
} ) ;
}
return out ;
} ;
/ *
* Removes all existing batches from the queue .
* /
ProductionQueue . prototype . ResetQueue = function ( )
{
// Empty the production queue and refund all the resource costs
// to the player. (This is to avoid players having to micromanage their
// buildings' queues when they're about to be destroyed or captured.)
while ( this . queue . length )
this . RemoveBatch ( this . queue [ 0 ] . id ) ;
} ;
2012-11-24 23:04:29 +01:00
/ *
* Returns batch build time .
* /
ProductionQueue . prototype . GetBatchTime = function ( batchSize )
{
var cmpPlayer = QueryOwnerInterface ( this . entity , IID _Player ) ;
2012-11-25 03:52:13 +01:00
2013-10-15 12:05:08 +02:00
var batchTimeModifier = ApplyValueModificationsToEntity ( "ProductionQueue/BatchTimeModifier" , + this . template . BatchTimeModifier , this . entity ) ;
2012-11-25 03:52:13 +01:00
2012-11-24 23:04:29 +01:00
// TODO: work out what equation we should use here.
2013-07-02 01:46:03 +02:00
return Math . pow ( batchSize , batchTimeModifier ) * cmpPlayer . GetCheatTimeMultiplier ( ) ;
2012-11-24 23:04:29 +01:00
} ;
2012-04-20 19:21:04 +02:00
ProductionQueue . prototype . OnOwnershipChanged = function ( msg )
{
if ( msg . from != - 1 )
{
// Unset flag that previous owner's training may be blocked
var cmpPlayer = QueryPlayerIDInterface ( msg . from , IID _Player ) ;
if ( cmpPlayer && this . queue . length > 0 )
cmpPlayer . UnBlockTraining ( ) ;
}
// 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 . OnDestroy = function ( )
{
// Reset the queue to refund any resources
this . ResetQueue ( ) ;
if ( this . timer )
{
var cmpTimer = Engine . QueryInterface ( SYSTEM _ENTITY , IID _Timer ) ;
cmpTimer . CancelTimer ( this . timer ) ;
}
} ;
/ *
2013-11-11 16:37:16 +01:00
* This function creates the entities and places them in world if possible
* and returns the number of successfully created entities .
* ( some of these entities may be garrisoned directly if autogarrison , the others are spawned ) .
2012-04-20 19:21:04 +02:00
* /
ProductionQueue . prototype . SpawnUnits = function ( templateName , count , metadata )
{
var cmpFootprint = Engine . QueryInterface ( this . entity , IID _Footprint ) ;
var cmpPosition = Engine . QueryInterface ( this . entity , IID _Position ) ;
var cmpOwnership = Engine . QueryInterface ( this . entity , IID _Ownership ) ;
var cmpRallyPoint = Engine . QueryInterface ( this . entity , IID _RallyPoint ) ;
2013-11-11 16:37:16 +01:00
var createdEnts = [ ] ;
2012-04-20 19:21:04 +02:00
var spawnedEnts = [ ] ;
if ( this . entityCache . length == 0 )
{
// We need entities to test spawning, but we don't want to waste resources,
// so only create them once and use as needed
for ( var i = 0 ; i < count ; ++ i )
{
2012-11-07 18:56:14 +01:00
var ent = Engine . AddEntity ( templateName ) ;
this . entityCache . push ( ent ) ;
// Decrement entity count in the EntityLimits component
// since it will be increased by EntityLimits.OnGlobalOwnershipChanged function,
// i.e. we replace a 'trained' entity to an 'alive' one
var cmpTrainingRestrictions = Engine . QueryInterface ( ent , IID _TrainingRestrictions ) ;
if ( cmpTrainingRestrictions )
{
var unitCategory = cmpTrainingRestrictions . GetCategory ( ) ;
var cmpPlayerEntityLimits = QueryOwnerInterface ( this . entity , IID _EntityLimits ) ;
cmpPlayerEntityLimits . DecrementCount ( unitCategory ) ;
}
2012-04-20 19:21:04 +02:00
}
}
2013-11-11 16:37:16 +01:00
var cmpAutoGarrison = undefined ;
if ( cmpRallyPoint )
{
var data = cmpRallyPoint . GetData ( ) [ 0 ] ;
if ( data && data . target == this . entity && data . command == "garrison" )
cmpAutoGarrison = Engine . QueryInterface ( this . entity , IID _GarrisonHolder ) ;
}
2012-04-20 19:21:04 +02:00
for ( var i = 0 ; i < count ; ++ i )
{
var ent = this . entityCache [ 0 ] ;
2013-11-11 16:37:16 +01:00
var cmpNewOwnership = Engine . QueryInterface ( ent , IID _Ownership ) ;
cmpNewOwnership . SetOwner ( cmpOwnership . GetOwner ( ) ) ;
if ( cmpAutoGarrison && cmpAutoGarrison . PerformGarrison ( ent ) )
2012-04-20 19:21:04 +02:00
{
2013-11-11 16:37:16 +01:00
var cmpUnitAI = Engine . QueryInterface ( ent , IID _UnitAI ) ;
cmpUnitAI . Autogarrison ( ) ;
2012-04-20 19:21:04 +02:00
}
else
{
2013-11-11 16:37:16 +01:00
var pos = cmpFootprint . PickSpawnPoint ( ent ) ;
if ( pos . y < 0 )
{
// Fail: there wasn't any space to spawn the unit
break ;
}
else
{
// Successfully spawned
var cmpNewPosition = Engine . QueryInterface ( ent , IID _Position ) ;
cmpNewPosition . JumpTo ( pos . x , pos . z ) ;
// TODO: what direction should they face in?
spawnedEnts . push ( ent ) ;
}
}
2012-04-20 19:21:04 +02:00
2013-11-11 16:37:16 +01:00
var cmpPlayerStatisticsTracker = QueryOwnerInterface ( this . entity , IID _StatisticsTracker ) ;
cmpPlayerStatisticsTracker . IncreaseTrainedUnitsCounter ( ) ;
2012-04-20 19:21:04 +02:00
2013-11-11 16:37:16 +01:00
// Play a sound, but only for the first in the batch (to avoid nasty phasing effects)
if ( createdEnts . length == 0 )
PlaySound ( "trained" , ent ) ;
2012-04-20 19:21:04 +02:00
2013-11-11 16:37:16 +01:00
this . entityCache . shift ( ) ;
createdEnts . push ( ent ) ;
2012-04-20 19:21:04 +02:00
}
2013-11-11 17:29:44 +01:00
if ( spawnedEnts . length > 0 && ! cmpAutoGarrison )
2012-04-20 19:21:04 +02:00
{
// If a rally point is set, walk towards it (in formation) using a suitable command based on where the
// rally point is placed.
if ( cmpRallyPoint )
{
2012-05-24 20:25:31 +02:00
var rallyPos = cmpRallyPoint . GetPositions ( ) [ 0 ] ;
2012-04-20 19:21:04 +02:00
if ( rallyPos )
{
2012-05-24 20:25:31 +02:00
var commands = GetRallyPointCommands ( cmpRallyPoint , spawnedEnts ) ;
for each ( var com in commands )
ProcessCommand ( cmpOwnership . GetOwner ( ) , com ) ;
2012-04-20 19:21:04 +02:00
}
}
2013-11-11 16:37:16 +01:00
}
2012-04-20 19:21:04 +02:00
2013-11-11 16:37:16 +01:00
if ( createdEnts . length > 0 )
{
2012-04-20 19:21:04 +02:00
Engine . PostMessage ( this . entity , MT _TrainingFinished , {
2013-11-11 16:37:16 +01:00
"entities" : createdEnts ,
2012-04-20 19:21:04 +02:00
"owner" : cmpOwnership . GetOwner ( ) ,
"metadata" : metadata ,
} ) ;
}
2013-11-11 16:37:16 +01:00
return createdEnts . length ;
2012-04-20 19:21:04 +02:00
} ;
/ *
* Increments progress on the first batch in the production queue , and blocks the
* queue if population limit is reached or some units failed to spawn .
* /
ProductionQueue . prototype . ProgressTimeout = function ( data )
{
2013-05-22 01:01:53 +02:00
// Check if the production is paused (eg the entity is garrisoned)
if ( this . paused )
return ;
2012-04-20 19:21:04 +02:00
// Allocate the 1000msecs 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)
var time = g _ProgressInterval ;
var cmpPlayer = QueryOwnerInterface ( this . entity , IID _Player ) ;
while ( time > 0 && this . queue . length )
{
var item = this . queue [ 0 ] ;
if ( ! item . productionStarted )
{
// If the item is a unit then do population checks
if ( item . unitTemplate )
{
// Batch's training hasn't started yet.
// Try to reserve the necessary population slots
2013-02-25 21:30:02 +01:00
item . neededSlots = cmpPlayer . TryReservePopulationSlots ( item . population * item . count ) ;
if ( item . neededSlots )
2012-04-20 19:21:04 +02:00
{
2013-02-25 21:30:02 +01:00
// Not enough slots available - don't train this batch now
2012-04-20 19:21:04 +02:00
// (we'll try again on the next timeout)
// Set flag that training is blocked
cmpPlayer . BlockTraining ( ) ;
break ;
}
// Unset flag that training is blocked
cmpPlayer . UnBlockTraining ( ) ;
}
2012-07-31 04:03:25 +02:00
if ( item . technologyTemplate )
{
// Mark the research as started.
var cmpTechnologyManager = QueryOwnerInterface ( this . entity , IID _TechnologyManager ) ;
cmpTechnologyManager . StartedResearch ( item . technologyTemplate ) ;
}
2012-04-20 19:21:04 +02:00
item . productionStarted = true ;
}
// If we won't finish the batch now, just update its timer
if ( item . timeRemaining > time )
{
item . timeRemaining -= time ;
2013-03-09 15:09:06 +01:00
// send a message for the AIs.
Engine . PostMessage ( this . entity , MT _ProductionQueueChanged , { } ) ;
2012-04-20 19:21:04 +02:00
break ;
}
if ( item . unitTemplate )
{
var numSpawned = this . SpawnUnits ( item . unitTemplate , item . count , item . metadata ) ;
if ( numSpawned == item . count )
{
// All entities spawned, this batch finished
cmpPlayer . UnReservePopulationSlots ( item . population * numSpawned ) ;
time -= item . timeRemaining ;
this . queue . shift ( ) ;
// Unset flag that training is blocked
cmpPlayer . UnBlockTraining ( ) ;
this . spawnNotified = false ;
Engine . PostMessage ( this . entity , MT _ProductionQueueChanged , { } ) ;
}
else
{
if ( numSpawned > 0 )
{
// Only partially finished
cmpPlayer . UnReservePopulationSlots ( item . population * numSpawned ) ;
item . count -= numSpawned ;
Engine . PostMessage ( this . entity , MT _ProductionQueueChanged , { } ) ;
}
// Some entities failed to spawn
// Set flag that training is blocked
cmpPlayer . BlockTraining ( ) ;
if ( ! this . spawnNotified )
{
var cmpPlayer = QueryOwnerInterface ( this . entity , IID _Player ) ;
var notification = { "player" : cmpPlayer . GetPlayerID ( ) , "message" : "Can't find free space to spawn trained units" } ;
var cmpGUIInterface = Engine . QueryInterface ( SYSTEM _ENTITY , IID _GuiInterface ) ;
cmpGUIInterface . PushNotification ( notification ) ;
this . spawnNotified = true ;
}
break ;
}
}
else if ( item . technologyTemplate )
{
var cmpTechnologyManager = QueryOwnerInterface ( this . entity , IID _TechnologyManager ) ;
cmpTechnologyManager . ResearchTechnology ( item . technologyTemplate ) ;
2013-09-09 14:50:05 +02:00
var template = cmpTechnologyManager . GetTechnologyTemplate ( item . technologyTemplate ) ;
if ( template && template . soundComplete )
{
var cmpSoundManager = Engine . QueryInterface ( SYSTEM _ENTITY , IID _SoundManager ) ;
if ( cmpSoundManager )
cmpSoundManager . PlaySoundGroup ( template . soundComplete , this . entity ) ;
}
2012-04-20 19:21:04 +02:00
time -= item . timeRemaining ;
this . queue . shift ( ) ;
Engine . PostMessage ( this . entity , MT _ProductionQueueChanged , { } ) ;
}
}
// If the queue's empty, delete the timer, else repeat it
if ( this . queue . length == 0 )
{
this . timer = undefined ;
// Unset flag that training is blocked
// (This might happen when the player unqueues all batches)
cmpPlayer . UnBlockTraining ( ) ;
}
else
{
var cmpTimer = Engine . QueryInterface ( SYSTEM _ENTITY , IID _Timer ) ;
this . timer = cmpTimer . SetTimeout ( this . entity , IID _ProductionQueue , "ProgressTimeout" , g _ProgressInterval , data ) ;
}
2013-05-22 01:01:53 +02:00
} ;
ProductionQueue . prototype . PauseProduction = function ( )
{
this . timer = undefined ;
this . paused = true ;
} ;
ProductionQueue . prototype . UnpauseProduction = function ( )
{
this . paused = false ;
var cmpTimer = Engine . QueryInterface ( SYSTEM _ENTITY , IID _Timer ) ;
this . timer = cmpTimer . SetTimeout ( this . entity , IID _ProductionQueue , "ProgressTimeout" , g _ProgressInterval , { } ) ;
} ;
2012-04-20 19:21:04 +02:00
Mythos_Ruler's Christmas update for SVN users!
Includes:
- Unit rank upgrades, based on a patch by Sanderd. Not all civs get all
rank upgrades. For instance, Spartans get the Infantry rank upgrades,
but not the cavalry rank upgrades. Conversely, the Persians get the
cavalry rank upgrades, but not the infantry rank upgrades. Carthaginians
get rank upgrades for their mercenaries, but not their native units.
etc.
- Updated and tweaked many of the skirmish maps. Too many tweaks to
mention. But I did add Iberian circuit walls to many of them! New
"Bactria" Skirmish Map. Will continue to tweak this one to make it more
unique. It's based on modern-day Afghanistan, which the ancients called
"Bactria." A 2nd Ptolemies sandbox demo map.
- Moved the Ptolemaic Lighthouse to Town Phase to have more impact for
the Ptolemy player on maps with water.
- New Thureos shield patterns by Enrique for a NEW unit: Mercenary
Thureos Spearman.
- TECHNOLOGIES: Some techs renamed and tweaked. Plus, a new "Iron Armor"
tech for Heroes. A new "Roman Logistics" tech for the Roman Army Camp
and Siege Walls. A new "Battlefield Medics" tech for the temple that
unlocks (slow) health regeneration for units. The portrait for this tech
is placeholder and needs replaced ASAP.
- Cavalry now have oval selection rings. Eventually I will implement a
selection ring system where the citizen-soldiers and support units have
round rings, while champions have arrows, and heroes have stars. This
helps visually differentiate the roles of these 3 classes of units. Not
yet implemented.
- Vision radius for infantry slightly reduced.
- Fixed sounds for Persian Wonder.
- Fixed footprint sizes for a few buildings and Ptolemaic walls.
- Ptolemies now have the "Military Settlement" system in place. But this
system might go to the Seleucids instead later for historical reasons.
- Cost of fields reduced. Gathering rates for grain reduced.
- Fixed some selection group names for some templates. (Double clicking
didn't select them all as it should have).
- Fixed/Changed/Added some unit and building names, specifically for the
Ptolemies, but for some others as well.
- Some new temp portraits for Ptolemaic units. Ongoing task.
Lastly, I hope these changes don't break anything. They are heavily
tested on my end, but I can't promise I caught all bugs.
This was SVN commit r14388.
2013-12-25 16:49:49 +01:00
ProductionQueue . 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" )
this . CalculateEntitiesList ( ) ;
} ;
2012-04-20 19:21:04 +02:00
Engine . RegisterComponentType ( IID _ProductionQueue , "ProductionQueue" , ProductionQueue ) ;