1
0
forked from 0ad/0ad

Added "Survival of the Fittest", a demo random map with triggers. Refs #52

This was SVN commit r15468.
This commit is contained in:
O.Davoodi 2014-06-30 13:59:34 +00:00
parent c339928c6f
commit 00fa45161d
5 changed files with 520 additions and 3 deletions

View File

@ -130,8 +130,8 @@ function createForests(terrainset, constraint, tileclass, numMultiplier, biomeID
var num = floor(size / types.length);
for (var i = 0; i < types.length; ++i)
{
placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), numForest / num, 0.5);
painter = new LayeredPainter(
var placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), numForest / num, 0.5);
var painter = new LayeredPainter(
types[i], // terrains
[2] // widths
);

View File

@ -0,0 +1,296 @@
RMS.LoadLibrary("rmgen");
//random terrain textures
var random_terrain = randomizeBiome();
const tMainTerrain = rBiomeT1();
const tForestFloor1 = rBiomeT2();
const tForestFloor2 = rBiomeT3();
const tCliff = rBiomeT4();
const tTier1Terrain = rBiomeT5();
const tTier2Terrain = rBiomeT6();
const tTier3Terrain = rBiomeT7();
const tHill = rBiomeT8();
const tDirt = rBiomeT9();
const tRoad = rBiomeT10();
const tRoadWild = rBiomeT11();
const tTier4Terrain = rBiomeT12();
const tShoreBlend = rBiomeT13();
const tShore = rBiomeT14();
const tWater = rBiomeT15();
// gaia entities
const oTree1 = rBiomeE1();
const oTree2 = rBiomeE2();
const oTree3 = rBiomeE3();
const oTree4 = rBiomeE4();
const oTree5 = rBiomeE5();
const oFruitBush = rBiomeE6();
const oChicken = rBiomeE7();
const oMainHuntableAnimal = rBiomeE8();
const oFish = rBiomeE9();
const oSecondaryHuntableAnimal = rBiomeE10();
const oStoneLarge = rBiomeE11();
const oStoneSmall = rBiomeE12();
const oMetalLarge = rBiomeE13();
const oWood = "gaia/special_treasure_wood";
const oFood = "gaia/special_treasure_food_bin";
// decorative props
const aGrass = rBiomeA1();
const aGrassShort = rBiomeA2();
const aReeds = rBiomeA3();
const aLillies = rBiomeA4();
const aRockLarge = rBiomeA5();
const aRockMedium = rBiomeA6();
const aBushMedium = rBiomeA7();
const aBushSmall = rBiomeA8();
const aTree = rBiomeA9();
const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2];
const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1];
const BUILDING_ANGlE = -PI/4;
// initialize map
log("Initializing map...");
InitMap();
var numPlayers = getNumPlayers() - 1;
var mapSize = getMapSize();
var mapArea = mapSize*mapSize;
// create tile classes
var clPlayer = createTileClass();
var clHill = createTileClass();
var clHill2 = createTileClass();
var clForest = createTileClass();
var clWater = createTileClass();
var clDirt = createTileClass();
var clRock = createTileClass();
var clMetal = createTileClass();
var clFood = createTileClass();
var clBaseResource = createTileClass();
var clSettlement = createTileClass();
var clLand = createTileClass();
var clWomen = createTileClass();
for (var ix = 0; ix < mapSize; ix++)
{
for (var iz = 0; iz < mapSize; iz++)
{
var x = ix / (mapSize + 1.0);
var z = iz / (mapSize + 1.0);
placeTerrain(ix, iz, tMainTerrain);
}
}
var fx = fractionToTiles(0.5);
var fz = fractionToTiles(0.5);
ix = round(fx);
iz = round(fz);
var lSize = sqrt(sqrt(sqrt(scaleByMapSize(1, 6))));
var placer = new ClumpPlacer(mapArea * 0.065 * lSize, 0.7, 0.1, 10, ix, iz);
var terrainPainter = new LayeredPainter(
[tMainTerrain, tMainTerrain], // terrains
[3] // widths
);
var elevationPainter = new SmoothElevationPainter(
ELEVATION_SET, // type
3, // elevation
3 // blend radius
);
createArea(placer, [terrainPainter, elevationPainter, paintClass(clLand)], null);
// randomize player order
var playerIDs = [];
for (var i = 0; i < numPlayers; i++)
{
playerIDs.push(i+1);
}
playerIDs = sortPlayers(playerIDs);
// place players
var playerX = new Array(numPlayers);
var playerZ = new Array(numPlayers);
var attackerX = new Array(numPlayers);
var attackerZ = new Array(numPlayers);
var playerAngle = new Array(numPlayers);
var startAngle = randFloat(0, TWO_PI);
for (var i = 0; i < numPlayers; i++)
{
playerAngle[i] = startAngle + i*TWO_PI/numPlayers;
playerX[i] = 0.5 + 0.3*cos(playerAngle[i]);
playerZ[i] = 0.5 + 0.3*sin(playerAngle[i]);
attackerX[i] = 0.5 + 0.45*cos(playerAngle[i]);
attackerZ[i] = 0.5 + 0.45*sin(playerAngle[i]);
}
// determines the trigger point associated with the attacker spawning point of each player.
var attackerTriggerPointForPlayer = ["", "B", "C", "D", "E", "F", "G", "H"];
for (var i = 0; i < numPlayers; i++)
{
var id = playerIDs[i];
log("Creating base for player " + id + "...");
// some constants
var radius = scaleByMapSize(15,25);
var cliffRadius = 2;
var elevation = 20;
// place the attacker spawning trigger point
var ax = round(fractionToTiles(attackerX[i]));
var az = round(fractionToTiles(attackerZ[i]));
placeObject(ax, az, "special/trigger_point_" + attackerTriggerPointForPlayer[id], 0, PI);
addToClass(ax, az, clPlayer);
addToClass(round(fractionToTiles((attackerX[i] + playerX[i]) / 2)), round(fractionToTiles((attackerZ[i] + playerZ[i]) / 2)), clPlayer);
// get the x and z in tiles
fx = fractionToTiles(playerX[i]);
fz = fractionToTiles(playerZ[i]);
ix = round(fx);
iz = round(fz);
addToClass(ix, iz, clPlayer);
addToClass(ix+5, iz, clPlayer);
addToClass(ix, iz+5, clPlayer);
addToClass(ix-5, iz, clPlayer);
addToClass(ix, iz-5, clPlayer);
// Place default civ starting entities
var uDist = 6;
var uSpace = 2;
placeObject(fx, fz, "skirmish/structures/default_civil_centre", id, BUILDING_ANGlE);
var uAngle = BUILDING_ANGlE - PI / 2;
var count = 4;
for (var numberofentities = 0; numberofentities < count; numberofentities++)
{
var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2));
var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2));
placeObject(ux, uz, "skirmish/units/default_infantry_melee_b", id, uAngle);
}
// create grass tufts
var num = radius * radius * 3.14 / 250;
for (var j = 0; j < num; j++)
{
var gAngle = randFloat(0, TWO_PI);
var gDist = radius - (5 + randInt(7));
var gX = round(fx + gDist * cos(gAngle));
var gZ = round(fz + gDist * sin(gAngle));
var group = new SimpleGroup(
[new SimpleObject(aGrassShort, 2,5, 0,1, -PI/8,PI/8)],
false, clBaseResource, gX, gZ
);
createObjectGroup(group, 0);
}
var tang = startAngle + (i+0.5)*TWO_PI/numPlayers;
var placer = new PathPlacer(fractionToTiles(0.5), fractionToTiles(0.5), fractionToTiles(0.5 + 0.5*cos(tang)), fractionToTiles(0.5 + 0.5*sin(tang)), scaleByMapSize(14,24), 0.4, 3*(scaleByMapSize(1,3)), 0.2, 0.05);
var terrainPainter = new LayeredPainter(
[tMainTerrain, tMainTerrain], // terrains
[1] // widths
);
var elevationPainter = new SmoothElevationPainter(
ELEVATION_SET, // type
3, // elevation
4 // blend radius
);
createArea(placer, [terrainPainter, elevationPainter, paintClass(clWater)], null);
//creating female citizens
var femaleLocation = getTIPIADBON([ix, iz], [mapSize / 2, mapSize / 2], [-3 , 3.5], 1, 3);
if (femaleLocation !== undefined)
{
placeObject(femaleLocation[0], femaleLocation[1], "skirmish/units/default_support_female_citizen", id, playerAngle[i] + PI);
addToClass(floor(femaleLocation[0]), floor(femaleLocation[1]), clWomen);
}
}
paintTerrainBasedOnHeight(3.12, 29, 1, tCliff);
paintTileClassBasedOnHeight(3.12, 29, 1, clHill);
// create trigger points for treasures
group = new SimpleGroup( [new SimpleObject("special/trigger_point_A", 1,1, 0,0)], true, clWomen);
createObjectGroups(group, 0,
[avoidClasses(clForest, 5, clPlayer, 5, clHill, 5), stayClasses(clLand, 5)],
scaleByMapSize(40, 140), 100
);
// create bumps
createBumps([avoidClasses(clWater, 2, clPlayer, 10), stayClasses(clLand, 5)]);
// create hills
if (randInt(1,2) == 1)
createHills([tMainTerrain, tCliff, tHill], [avoidClasses(clPlayer, 20, clHill, 5, clBaseResource, 3, clWomen, 5), stayClasses(clLand, 5)], clHill, scaleByMapSize(10, 60) * numPlayers);
else
createMountains(tCliff, [avoidClasses(clPlayer, 20, clHill, 5, clBaseResource, 3, clWomen, 5), stayClasses(clLand, 5)], clHill, scaleByMapSize(10, 60) * numPlayers);
createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 20, clHill, 5, clBaseResource, 3, clWomen, 5, clLand, 5), clHill, scaleByMapSize(15, 90) * numPlayers, undefined, undefined, undefined, undefined, 55);
// create forests
createForests(
[tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2],
[avoidClasses(clPlayer, 20, clForest, 5, clHill, 0, clBaseResource,2, clWomen, 5), stayClasses(clLand, 4)],
clForest,
1.0,
random_terrain
);
RMS.SetProgress(50);
// create dirt patches
log("Creating dirt patches...");
createLayeredPatches(
[scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)],
[[tMainTerrain,tTier1Terrain],[tTier1Terrain,tTier2Terrain], [tTier2Terrain,tTier3Terrain]],
[1,1],
[avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12, clWomen, 5), stayClasses(clLand, 5)]
);
// create grass patches
log("Creating grass patches...");
createPatches(
[scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)],
tTier4Terrain,
[avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12, clWomen, 5), stayClasses(clLand, 5)]
);
// create decoration
var planetm = 1;
if (random_terrain==7)
planetm = 8;
createDecoration
(
[[new SimpleObject(aRockMedium, 1,3, 0,1)],
[new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)],
[new SimpleObject(aGrassShort, 1,2, 0,1, -PI/8,PI/8)],
[new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)],
[new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)]
],
[
scaleByMapSize(16, 262),
scaleByMapSize(8, 131),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200)
],
[avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 5)]
);
// create straggler trees
log("Creating straggler trees...");
var types = [oTree1, oTree2, oTree4, oTree3]; // some variation
createStragglerTrees(types, [avoidClasses(clForest, 7, clHill, 1, clPlayer, 9, clMetal, 1, clRock, 1), stayClasses(clLand, 7)]);
// Export map data
ExportMap();

View File

@ -0,0 +1,16 @@
{
"settings" : {
"Name" : "Survival of the Fittest",
"Script" : "survivalofthefittest.js",
"Description" : "IMPORTANT NOTE: SET THE LAST PLAYER TO UNDEFINED AI.\n\nAI PLAYERS WONT WORK WITH THIS MAP\n\nProtect your base against endless waves of enemies. Use your woman citizen to gather resources. The last player remaining will be the winner.",
"BaseTerrain" : ["medit_sea_depths"],
"BaseHeight" : 30,
"CircularMap" : true,
"Keywords": ["demo"],
"TriggerScripts": [
"scripts/TriggerHelper.js",
"random/survivalofthefittest_triggers.js"
],
"XXXXXX" : "Optionally define other things here, like we would for a scenario"
}
}

View File

@ -0,0 +1,171 @@
var attackerTriggerPointForPlayer = ["", "B", "C", "D", "E", "F", "G", "H"];
var numberOfPlayers = TriggerHelper.GetNumberOfPlayers() - 1;
var treasures = ["gaia/special_treasure_food_barrel",
"gaia/special_treasure_food_bin",
"gaia/special_treasure_food_crate",
"gaia/special_treasure_food_jars",
"gaia/special_treasure_metal",
"gaia/special_treasure_stone",
"gaia/special_treasure_wood",
"gaia/special_treasure_wood",
"gaia/special_treasure_wood"];
var attackerEntityTemplates = ["units/athen_champion_infantry",
"units/athen_champion_marine",
"units/athen_champion_ranged",
"units/brit_champion_cavalry",
"units/brit_champion_infantry",
"units/cart_champion_cavalry",
"units/cart_champion_elephant",
"units/cart_champion_infantry",
"units/cart_champion_pikeman",
"units/gaul_champion_cavalry",
"units/gaul_champion_fanatic",
"units/gaul_champion_infantry",
"units/iber_champion_cavalry",
"units/iber_champion_infantry",
"units/mace_champion_cavalry",
"units/mace_champion_infantry_a",
"units/mace_champion_infantry_e",
"units/maur_champion_chariot",
"units/maur_champion_elephant",
"units/maur_champion_infantry",
"units/maur_champion_maiden",
"units/maur_champion_maiden_archer",
"units/pers_champion_cavalry",
"units/pers_champion_infantry",
"units/ptol_champion_cavalry",
"units/ptol_champion_elephant",
"units/rome_champion_cavalry",
"units/rome_champion_infantry",
"units/sele_champion_cavalry",
"units/sele_champion_chariot",
"units/sele_champion_elephant",
"units/sele_champion_infantry_pikeman",
"units/sele_champion_infantry_swordsman",
"units/spart_champion_infantry_pike",
"units/spart_champion_infantry_spear",
"units/spart_champion_infantry_sword"];
Trigger.prototype.StartAnEnemyWave = function()
{
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
var attackerEntity = attackerEntityTemplates[Math.floor(Math.random() * attackerEntityTemplates.length)];
var attackerCount = cmpTimer.GetTime() / 180000; // A soldier for each 3 minutes of the game. Should be waves of 20 soldiers after an hour
for (var i = 1; i < numberOfPlayers; ++i)
{
if (TriggerHelper.GetPlayerComponent(i).GetState() == "active") // If the player isn't yet defeated
{
// spawn attackers
var attackers = TriggerHelper.SpawnUnitsFromTriggerPoints(attackerTriggerPointForPlayer[i], attackerEntity, attackerCount, numberOfPlayers);
// order them to attack
for (var attacker in attackers)
{
var cmpPosition = Engine.QueryInterface(cmpTrigger.playerCivicCenter[i], IID_Position);
if (!cmpPosition || !cmpPosition.IsInWorld)
break;
// store the x and z coordinates in the command
var cmd = cmpPosition.GetPosition();
cmd.type = "attack-walk";
cmd.entities = attackers[attacker];
cmd.queued = true;
ProcessCommand(numberOfPlayers, cmd);
}
}
}
var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
cmpGUIInterface.PushNotification({
"players": [1,2,3,4,5,6,7,8],
"message": markForTranslation("An enemy wave is attacking!"),
"translateMessage": true
});
cmpTrigger.DoAfterDelay(180000, "StartAnEnemyWave", {}); // The next wave will come in 3 minutes
}
Trigger.prototype.InitGame = function()
{
// Find all of the civic centers
for (var i = 1; i < numberOfPlayers; ++i)
{
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
var playerEntities = cmpRangeManager.GetEntitiesByPlayer(i); // Get all of each player's entities
for each (var entity in playerEntities)
{
if (TriggerHelper.EntityHasClass(entity, "CivilCentre"))
{
cmpTrigger.playerCivicCenter[i] = entity;
}
}
}
// Fix alliances
for (var i = 1; i < numberOfPlayers; ++i)
{
var cmpPlayer = TriggerHelper.GetPlayerComponent(i);
for (var j = 1; j < numberOfPlayers; ++j)
if (i != j)
cmpPlayer.SetAlly(j);
cmpPlayer.SetEnemy(numberOfPlayers);
cmpPlayer.SetLockTeams(true);
}
// Place the treasures
cmpTrigger.DoAction({action: "PlaceTreasures"});
// Additional stuff
var cmpPlayer = TriggerHelper.GetPlayerComponent(numberOfPlayers);
cmpPlayer.SetName("Enemy Waves");
}
Trigger.prototype.PlaceTreasures = function()
{
var triggerPoints = cmpTrigger.GetTriggerPoints("A");
for (var point of triggerPoints)
{
var template = treasures[Math.floor(Math.random() * treasures.length)]
TriggerHelper.SpawnUnits(point, template, 1, 0);
}
cmpTrigger.DoAfterDelay(240000, "PlaceTreasures", {}); //Place more treasures after 4 minutes
}
Trigger.prototype.InitializeEnemyWaves = function()
{
var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
cmpGUIInterface.PushNotification({
"players": [1,2,3,4,5,6,7,8],
"message": markForTranslation("The first wave will start in 15 minutes!"),
"translateMessage": true
});
cmpTrigger.DoAfterDelay(900000, "StartAnEnemyWave", {});
}
Trigger.prototype.DefeatPlayerOnceCCIsDestroyed = function(data)
{
// Defeat a player that has lost his civic center
if ( data.entity == cmpTrigger.playerCivicCenter[data.from] && data.to == -1)
TriggerHelper.DefeatPlayer(data.from);
// Check if only one player remains. He will be the winner.
var lastPlayerStanding = 0;
var numPlayersStanding = 0;
for (var i = 1; i < numberOfPlayers; ++i)
{
if (TriggerHelper.GetPlayerComponent(i).GetState() == "active")
{
lastPlayerStanding = i;
++numPlayersStanding;
}
}
if (numPlayersStanding == 1)
TriggerHelper.SetPlayerWon(lastPlayerStanding);
}
var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
cmpTrigger.playerCivicCenter = {};
cmpTrigger.DoAfterDelay(0, "InitGame", {});
cmpTrigger.DoAfterDelay(1000, "InitializeEnemyWaves", {});
cmpTrigger.RegisterTrigger("OnOwnershipChanged", "DefeatPlayerOnceCCIsDestroyed", {"enabled": true});

View File

@ -125,8 +125,42 @@ TriggerHelper.SetPlayerWon = function(playerID)
*/
TriggerHelper.DefeatPlayer = function(playerID)
{
var playerEnt = GetPlayerEntityByID(playerID);
var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
var playerEnt = cmpPlayerMan.GetPlayerByID(playerID);
Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": playerID } );
};
/**
* Returns the number of current players
*/
TriggerHelper.GetNumberOfPlayers = function()
{
var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
return cmpPlayerManager.GetNumPlayers();
}
/**
* Returns the player component. For more information on its functions, see simulation/components/Player.js
*/
TriggerHelper.GetPlayerComponent = function(playerID)
{
var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
return Engine.QueryInterface(cmpPlayerMan.GetPlayerByID(playerID), IID_Player);
}
/**
* A function to determine if an entity has a specific class
* @param entity ID of the entity that we want to check for classes
* @param classname The name of the class we are checking if the entity has
*/
TriggerHelper.EntityHasClass = function(entity, classname)
{
var cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
if (!cmpIdentity)
return false;
var classes = cmpIdentity.GetClassesList();;
return (classes && classes.indexOf(classname) != -1);
}
Engine.RegisterGlobal("TriggerHelper", TriggerHelper);