forked from mirrors/0ad
Spawn attackers at the gaia civic centers on Danubius, so as to make the more frightening and incentivize its destruction.
Differential Revision: https://code.wildfiregames.com/D380 Reviewed By: Sandarac This was SVN commit r19707.
This commit is contained in:
@@ -7,6 +7,8 @@ const triggerPointShipUnloadLeft = "special/trigger_point_C";
|
||||
const triggerPointShipUnloadRight = "special/trigger_point_D";
|
||||
const triggerPointLandPatrolLeft = "special/trigger_point_E";
|
||||
const triggerPointLandPatrolRight = "special/trigger_point_F";
|
||||
const triggerPointCCAttackerPatrolLeft = "special/trigger_point_G";
|
||||
const triggerPointCCAttackerPatrolRight = "special/trigger_point_H";
|
||||
|
||||
// Terrain textures
|
||||
const tRoad = "steppe_river_rocks";
|
||||
@@ -123,11 +125,13 @@ InitMap();
|
||||
const numPlayers = getNumPlayers();
|
||||
const mapSize = getMapSize();
|
||||
|
||||
var clMiddle = createTileClass();
|
||||
var clPlayer = createTileClass();
|
||||
var clForest = createTileClass();
|
||||
var clWater = createTileClass();
|
||||
var clLand = [createTileClass(), createTileClass()];
|
||||
var clLandPatrolPoint = [createTileClass(), createTileClass()];
|
||||
var clCCAttackerPatrolPoint = [createTileClass(), createTileClass()];
|
||||
var clShore = [createTileClass(), createTileClass()];
|
||||
var clShoreUngarrisonPoint = [createTileClass(), createTileClass()];
|
||||
var clShip = createTileClass();
|
||||
@@ -156,8 +160,9 @@ var gallicCCTreasureCount = randIntInclusive(8, 12);
|
||||
// How many treasures will be placed randomly on the map at most
|
||||
var randomTreasureCount = randIntInclusive(0, 3 * numPlayers);
|
||||
|
||||
// Place a gaia village on small maps and larger
|
||||
if (mapSize >= smallMapSize)
|
||||
// Place a gallic village on small maps and larger
|
||||
var gallicCC = mapSize >= smallMapSize;
|
||||
if (gallicCC)
|
||||
{
|
||||
log("Creating gallic villages...");
|
||||
let gaulCityRadius = 12;
|
||||
@@ -186,7 +191,7 @@ if (mapSize >= smallMapSize)
|
||||
// Radius of the meeting place
|
||||
let mRadius = scaleByMapSize(4, 6);
|
||||
|
||||
// Create a path connecting the gaia city with a meeting place at the shoreline.
|
||||
// Create a path connecting the gallic city with a meeting place at the shoreline.
|
||||
// To avoid the path going through the palisade wall, start it at the gate, not at the city center.
|
||||
let placer = new PathPlacer(
|
||||
gX + gaulCityRadius * (i == 0 ? 1 : -1),
|
||||
@@ -273,7 +278,7 @@ if (mapSize >= smallMapSize)
|
||||
let wall = [
|
||||
"gate", "hut", "palisade_tower", "wallLong", "wallLong",
|
||||
"cornerIn", "defense_tower", "wallLong", "wallLong", "temple",
|
||||
"palisade_tower", "wallLong", "house", "wallLong", "palisade_tower", "longhouse", "wallLong", "wallLong",
|
||||
"palisade_tower", "wallLong", "house", "gate", "palisade_tower", "longhouse", "wallLong", "wallLong",
|
||||
"cornerIn", "defense_tower", "wallLong", "tavern", "wallLong", "palisade_tower"];
|
||||
wall = wall.concat(wall);
|
||||
placeCustomFortress(gX, gZ, new Fortress("Geto-Dacian Tribal Confederation", wall), "gaul", 0, PI);
|
||||
@@ -776,7 +781,9 @@ for (let i = 0; i < 2; ++i)
|
||||
);
|
||||
|
||||
log("Creating patrol points for land attackers...");
|
||||
addToClass(mapSize/2, mapSize/2, clMiddle);
|
||||
for (let i = 0; i < 2; ++i)
|
||||
{
|
||||
createObjectGroups(
|
||||
new SimpleGroup(
|
||||
[new SimpleObject(
|
||||
@@ -794,6 +801,35 @@ for (let i = 0; i < 2; ++i)
|
||||
100
|
||||
);
|
||||
|
||||
if (gallicCC)
|
||||
createObjectGroups(
|
||||
new SimpleGroup(
|
||||
[new SimpleObject(
|
||||
i == 0 ? triggerPointCCAttackerPatrolLeft : triggerPointCCAttackerPatrolRight,
|
||||
1, 1,
|
||||
0, 0)],
|
||||
true,
|
||||
clCCAttackerPatrolPoint[i]),
|
||||
0,
|
||||
[
|
||||
// Don't avoid the forest, so that as many places as possible on the border are visited
|
||||
avoidClasses(
|
||||
clWater, 5,
|
||||
clHill, 3,
|
||||
clFood, 1,
|
||||
clRock, 4,
|
||||
clMetal, 4,
|
||||
clPlayer, 15,
|
||||
clGauls, 0,
|
||||
clCCAttackerPatrolPoint[i], 5,
|
||||
clMiddle, mapSize * 0.5 - 15),
|
||||
stayClasses(clLand[i], 0)
|
||||
],
|
||||
10000,
|
||||
100
|
||||
);
|
||||
}
|
||||
|
||||
log("Creating water logs...");
|
||||
createObjectGroups(
|
||||
new SimpleGroup([new SimpleObject(aWaterLog, 1, 1, 0, 0)], true, clWaterLog),
|
||||
|
||||
@@ -78,6 +78,16 @@ var gallicBuildingGarrison = [
|
||||
* This can be accomplished by not wiping out players buildings entirely.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Time in minutes between two consecutive waves spawned from the gaia civic centers, if they still exist.
|
||||
*/
|
||||
var ccAttackerInterval = t => randFloat(6, 8);
|
||||
|
||||
/**
|
||||
* Number of attackers spawned at a civic center at t minutes ingame time.
|
||||
*/
|
||||
var ccAttackerCount = t => Math.min(20, Math.max(0, Math.round(t * 1.5)));
|
||||
|
||||
/**
|
||||
* Time between two consecutive waves.
|
||||
*/
|
||||
@@ -189,6 +199,8 @@ var triggerPointUngarrisonLeft = "C";
|
||||
var triggerPointUngarrisonRight = "D";
|
||||
var triggerPointLandPatrolLeft = "E";
|
||||
var triggerPointLandPatrolRight = "F";
|
||||
var triggerPointCCAttackerPatrolLeft = "G";
|
||||
var triggerPointCCAttackerPatrolRight = "H";
|
||||
|
||||
/**
|
||||
* Which playerID to use for the opposing gallic reinforcements.
|
||||
@@ -266,7 +278,7 @@ Trigger.prototype.SpawnAndGarrisonBuilding = function(gaiaEnts, targetClass, tem
|
||||
/**
|
||||
* Spawn units of the template at each gaia Civic Center and set them to defensive.
|
||||
*/
|
||||
Trigger.prototype.SpawnCCDefenders = function(gaiaEnts)
|
||||
Trigger.prototype.SpawnInitialCCDefenders = function(gaiaEnts)
|
||||
{
|
||||
this.debugLog("To defend CCs, spawning " + uneval(ccDefenders));
|
||||
|
||||
@@ -276,12 +288,47 @@ Trigger.prototype.SpawnCCDefenders = function(gaiaEnts)
|
||||
if (!cmpIdentity || !cmpIdentity.HasClass("CivCentre"))
|
||||
continue;
|
||||
|
||||
this.civicCenters.push(gaiaEnt);
|
||||
|
||||
for (let ccDefender of ccDefenders)
|
||||
for (let ent of TriggerHelper.SpawnUnits(gaiaEnt, ccDefender.template, ccDefender.count, gaulPlayer))
|
||||
Engine.QueryInterface(ent, IID_UnitAI).SwitchToStance("defensive");
|
||||
}
|
||||
};
|
||||
|
||||
Trigger.prototype.SpawnCCAttackers = function()
|
||||
{
|
||||
let time = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer).GetTime() / 60 / 1000;
|
||||
let mapSize = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain).GetMapSize();
|
||||
|
||||
for (let gaiaCC of this.civicCenters)
|
||||
{
|
||||
let toSpawn = this.GetAttackerComposition(ccAttackerCount(time), false);
|
||||
this.debugLog("Spawning civic center attackers at " + gaiaCC + ": " + uneval(toSpawn));
|
||||
|
||||
let ccAttackers = [];
|
||||
|
||||
for (let spawn of toSpawn)
|
||||
{
|
||||
let ents = TriggerHelper.SpawnUnits(gaiaCC, "units/" + spawn.template, spawn.count, gaulPlayer);
|
||||
|
||||
if (spawn.hero && ents[0])
|
||||
this.heroes.push({ "template": spawn.template, "ent": ents[0] });
|
||||
|
||||
ccAttackers = ccAttackers.concat(ents);
|
||||
}
|
||||
|
||||
let patrolPointRef = Engine.QueryInterface(gaiaCC, IID_Position).GetPosition2D().x < mapSize / 2 ?
|
||||
triggerPointCCAttackerPatrolLeft :
|
||||
triggerPointCCAttackerPatrolRight;
|
||||
|
||||
this.AttackAndPatrol(ccAttackers, unitTargetClass, patrolPointRef, "CCAttackers", false);
|
||||
}
|
||||
|
||||
if (this.civicCenters.length)
|
||||
this.DoAfterDelay(ccAttackerInterval() * 60 * 1000, "SpawnCCAttackers", {});
|
||||
};
|
||||
|
||||
/**
|
||||
* Remember most Humans present at the beginning of the match (before spawning any unit) and
|
||||
* make them defensive.
|
||||
@@ -351,7 +398,7 @@ Trigger.prototype.SpawnShips = function()
|
||||
for (let ship of this.ships)
|
||||
this.AttackAndPatrol([ship], shipTargetClass, triggerPointShipPatrol, "Ships");
|
||||
|
||||
this.DoAfterDelay(shipRespawnTime() * 60 * 1000, "SpawnShips", {});
|
||||
this.DoAfterDelay(shipRespawnTime(time) * 60 * 1000, "SpawnShips", {});
|
||||
|
||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
||||
cmpTimer.CancelTimer(this.fillShipsTimer);
|
||||
@@ -359,61 +406,65 @@ Trigger.prototype.SpawnShips = function()
|
||||
this.FillShips();
|
||||
};
|
||||
|
||||
Trigger.prototype.GetAttackerComposition = function(attackerCount, addSiege)
|
||||
{
|
||||
let time = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer).GetTime() / 60 / 1000;
|
||||
let toSpawn = [];
|
||||
let remainder = attackerCount;
|
||||
|
||||
let siegeCount = addSiege ? Math.round(siegeRatio(time) * remainder) : 0;
|
||||
if (siegeCount)
|
||||
toSpawn.push({ "template": siegeTemplate, "count": siegeCount });
|
||||
remainder -= siegeCount;
|
||||
|
||||
let heroTemplate = pickRandom(heroTemplates.filter(hTemp => this.heroes.every(hero => hTemp != hero.template)));
|
||||
if (heroTemplate && remainder && randBool(heroProbability(time)))
|
||||
{
|
||||
toSpawn.push({ "template": heroTemplate, "count": 1, "hero": true });
|
||||
--remainder;
|
||||
}
|
||||
|
||||
let healerCount = Math.round(healerRatio(time) * remainder);
|
||||
if (healerCount)
|
||||
toSpawn.push({ "template": healerTemplate, "count": healerCount });
|
||||
remainder -= healerCount;
|
||||
|
||||
let championCount = Math.round(championRatio(time) * remainder);
|
||||
let championTemplateCounts = this.RandomAttackerTemplates(championTemplates, championCount);
|
||||
for (let template in championTemplateCounts)
|
||||
{
|
||||
let count = championTemplateCounts[template];
|
||||
toSpawn.push({ "template": template, "count": count });
|
||||
championCount -= count;
|
||||
remainder -= count;
|
||||
}
|
||||
|
||||
let citizenTemplateCounts = this.RandomAttackerTemplates(citizenTemplates, remainder);
|
||||
for (let template in citizenTemplateCounts)
|
||||
{
|
||||
let count = citizenTemplateCounts[template];
|
||||
toSpawn.push({ "template": template, "count": count });
|
||||
remainder -= count;
|
||||
}
|
||||
|
||||
if (remainder != 0)
|
||||
warn("Didn't spawn as many attackers as were intended (" + remainder + " remaining)");
|
||||
|
||||
return toSpawn;
|
||||
};
|
||||
|
||||
Trigger.prototype.FillShips = function()
|
||||
{
|
||||
let time = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer).GetTime() / 60 / 1000;
|
||||
let attackerCount = attackersPerShip(time);
|
||||
|
||||
for (let ship of this.ships)
|
||||
{
|
||||
let cmpGarrisonHolder = Engine.QueryInterface(ship, IID_GarrisonHolder);
|
||||
if (!cmpGarrisonHolder)
|
||||
continue;
|
||||
|
||||
let remainder = Math.max(0, attackerCount - cmpGarrisonHolder.GetEntities().length);
|
||||
|
||||
let toSpawn = [];
|
||||
|
||||
let siegeCount = Math.round(siegeRatio(time) * remainder);
|
||||
if (siegeCount)
|
||||
toSpawn.push({ "template": siegeTemplate, "count": siegeCount });
|
||||
remainder -= siegeCount;
|
||||
|
||||
let heroTemplate = pickRandom(heroTemplates.filter(hTemp => this.heroes.every(hero => hTemp != hero.template)));
|
||||
if (heroTemplate && remainder && randBool(heroProbability(time)))
|
||||
{
|
||||
toSpawn.push({ "template": heroTemplate, "count": 1, "hero": true });
|
||||
--remainder;
|
||||
}
|
||||
|
||||
let healerCount = Math.round(healerRatio(time) * remainder);
|
||||
if (healerCount)
|
||||
toSpawn.push({ "template": healerTemplate, "count": healerCount });
|
||||
remainder -= healerCount;
|
||||
|
||||
let championCount = Math.round(championRatio(time) * remainder);
|
||||
let championTemplateCounts = this.RandomAttackerTemplates(championTemplates, championCount);
|
||||
for (let template in championTemplateCounts)
|
||||
{
|
||||
let count = championTemplateCounts[template];
|
||||
toSpawn.push({ "template": template, "count": count });
|
||||
championCount -= count;
|
||||
remainder -= count;
|
||||
}
|
||||
|
||||
let citizenTemplateCounts = this.RandomAttackerTemplates(citizenTemplates, remainder);
|
||||
for (let template in citizenTemplateCounts)
|
||||
{
|
||||
let count = citizenTemplateCounts[template];
|
||||
toSpawn.push({ "template": template, "count": count });
|
||||
remainder -= count;
|
||||
}
|
||||
|
||||
let toSpawn = this.GetAttackerComposition(Math.max(0, attackersPerShip(time) - cmpGarrisonHolder.GetEntities().length), true);
|
||||
this.debugLog("Filling ship " + ship + " with " + uneval(toSpawn));
|
||||
|
||||
if (remainder != 0)
|
||||
warn("Didn't spawn as many attackers as were intended (" + remainder + " remaining)");
|
||||
|
||||
for (let spawn of toSpawn)
|
||||
{
|
||||
// Don't use TriggerHelper.SpawnUnits here because that is too slow,
|
||||
@@ -438,7 +489,7 @@ Trigger.prototype.FillShips = function()
|
||||
/**
|
||||
* Attack the closest enemy ships around, then patrol the sea.
|
||||
*/
|
||||
Trigger.prototype.AttackAndPatrol = function(attackers, targetClass, triggerPointRef, debugName)
|
||||
Trigger.prototype.AttackAndPatrol = function(attackers, targetClass, triggerPointRef, debugName, attack = true)
|
||||
{
|
||||
if (!attackers.length)
|
||||
return;
|
||||
@@ -453,14 +504,15 @@ Trigger.prototype.AttackAndPatrol = function(attackers, targetClass, triggerPoin
|
||||
|
||||
this.debugLog(debugName + " " + uneval(attackers) + " attack " + uneval(targets));
|
||||
|
||||
for (let target of targets)
|
||||
ProcessCommand(gaulPlayer, {
|
||||
"type": "attack",
|
||||
"entities": attackers,
|
||||
"target": target,
|
||||
"queued": true,
|
||||
"allowCapture": false
|
||||
});
|
||||
if (attack)
|
||||
for (let target of targets)
|
||||
ProcessCommand(gaulPlayer, {
|
||||
"type": "attack",
|
||||
"entities": attackers,
|
||||
"target": target,
|
||||
"queued": true,
|
||||
"allowCapture": false
|
||||
});
|
||||
|
||||
let patrolTargets = shuffleArray(this.GetTriggerPoints(triggerPointRef)).slice(0, patrolCount);
|
||||
this.debugLog(debugName + " " + uneval(attackers) + " patrol to " + uneval(patrolTargets));
|
||||
@@ -617,6 +669,13 @@ Trigger.prototype.DanubiusOwnershipChange = function(data)
|
||||
let heroIdx = this.heroes.findIndex(hero => hero.ent == data.entity);
|
||||
if (ritualIdx != -1)
|
||||
this.heroes.splice(heroIdx, 1);
|
||||
|
||||
let ccIdx = this.civicCenters.indexOf(data.entity);
|
||||
if (ccIdx != -1)
|
||||
{
|
||||
this.debugLog("Gaia civic center " + data.entity + " destroyed");
|
||||
this.civicCenters.splice(ccIdx, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -631,13 +690,17 @@ Trigger.prototype.DanubiusOwnershipChange = function(data)
|
||||
cmpTrigger.ships = [];
|
||||
cmpTrigger.heroes = [];
|
||||
|
||||
// Remember gaia CCs to spawn attackers from
|
||||
cmpTrigger.civicCenters = [];
|
||||
|
||||
// Maps from gaia ship entity ID to ungarrison trigger point entity ID and land patrol triggerpoint name
|
||||
cmpTrigger.shipTarget = {};
|
||||
cmpTrigger.fillShipsTimer = undefined;
|
||||
|
||||
cmpTrigger.StartCelticRitual(gaiaEnts);
|
||||
cmpTrigger.GarrisonAllGallicBuildings(gaiaEnts);
|
||||
cmpTrigger.SpawnCCDefenders(gaiaEnts);
|
||||
cmpTrigger.SpawnInitialCCDefenders(gaiaEnts);
|
||||
cmpTrigger.SpawnCCAttackers(gaiaEnts);
|
||||
|
||||
cmpTrigger.SpawnShips();
|
||||
cmpTrigger.DoAfterDelay(shipUngarrisonInterval() * 60 * 1000, "UngarrisonShipsOrder", {});
|
||||
|
||||
Reference in New Issue
Block a user