Open source Star Ruler 2 source code!

This commit is contained in:
Lucas de Vries
2018-07-17 14:15:37 +02:00
commit cc307720ff
4342 changed files with 2365070 additions and 0 deletions
+276
View File
@@ -0,0 +1,276 @@
#include "include/map.as"
enum MapSetting {
M_SystemCount,
M_SystemSpacing,
M_Flatten,
};
#section server
class Room {
vec3d position;
uint circle = 0;
SystemData@ core;
array<SystemData@> systems;
array<uint> circles;
array<Room@> corrids;
};
#section all
class ClustersMap : Map {
ClustersMap() {
super();
name = locale::CLUSTERS_MAP;
description = locale::CLUSTERS_MAP_DESC;
sortIndex = -100;
color = 0xd8ff00ff;
icon = "maps/Clusters/clusters.png";
}
#section client
void makeSettings() {
Number(locale::SYSTEM_COUNT, M_SystemCount, DEFAULT_SYSTEM_COUNT, decimals=0, step=10, min=20, halfWidth=true);
Number(locale::SYSTEM_SPACING, M_SystemSpacing, DEFAULT_SPACING, decimals=0, step=1000, min=MIN_SPACING, halfWidth=true);
Toggle(locale::FLATTEN, M_Flatten, false, halfWidth=true);
}
#section server
void placeSystems() {
uint systemCount = uint(getSetting(M_SystemCount, DEFAULT_SYSTEM_COUNT));
double spacing = modSpacing(getSetting(M_SystemSpacing, DEFAULT_SPACING));
bool flatten = getSetting(M_Flatten, 0.0) != 0.0;
//Calculate amount of 'rooms'
uint roomCnt = max(ceil(pow(double(systemCount), 0.33)), double(max(estPlayerCount+1, 4)));
uint corridorLength = clamp(ceil(double(systemCount) / 50.0), 1, 5);
uint sysPerRoom = max(double(systemCount) / double(roomCnt) - double(corridorLength), 4.0);
if(sysPerRoom % 2 != 0)
sysPerRoom -= 1;
double roomRadius = spacing * 1.5 * sqrt(double(sysPerRoom)) + spacing;
double glxRadius = roomRadius * sqrt(double(roomCnt));
double roomHeightVar = flatten ? 0.0 : roomRadius * 0.2;
double sysHeightVar = flatten ? 0.0 : spacing * 0.25;
//Generate rooms
double angle = 0.0;
double radius = 0.0;
double angleStep = twopi;
double anglePct = 0.0;
double startAngle = randomd(0.0, twopi);
array<Room@> rooms;
Room@ circleStart;
uint circle = 0;
uint circleCnt = 0;
for(uint i = 0; i < roomCnt; ++i) {
Room room;
room.position = quaterniond_fromAxisAngle(vec3d_up(), angle + startAngle) * vec3d_front(radius);
room.position.y = randomd(-roomHeightVar, roomHeightVar);
room.circle = circle;
//Make room connections
if(rooms.length != 0 && (roomCnt-i+circleCnt) > 2) {
if(rooms[i-1].circle == circle)
room.corrids.insertLast(rooms[i-1]);
}
if(circleStart is null)
@circleStart = room;
rooms.insertLast(room);
++circleCnt;
//Generate links to previous circle
if(circle > 0) {
Room@ closest;
double closestDist = INFINITY;
Room@ second;
double secondDist = INFINITY;
for(int j = int(i); j >= 0; --j) {
if(rooms[j].circle < circle-1)
break;
if(rooms[j].circle > circle-1)
continue;
Room@ other = rooms[j];
double d = other.position.distanceToSQ(room.position);
if(d < closestDist) {
@second = closest;
secondDist = closestDist;
closestDist = d;
@closest = other;
}
else if(d < secondDist) {
@second = other;
secondDist = d;
}
}
if(closest !is null)
room.corrids.insertLast(closest);
if(second !is null)
room.corrids.insertLast(second);
}
//Proceed to next room position
angle += angleStep;
if(angle + angleStep > twopi) {
angle = 0.0;
radius += roomRadius;
startAngle = randomd(0.0, twopi);
anglePct = (roomRadius / (2.0 * pi * radius));
if(roomCnt - i - 1 > 0)
angleStep = max(anglePct * twopi, twopi / double(roomCnt - i - 1));
circle += 1;
if(circleStart !is null && circle != 1 && circleStart !is room && circleCnt > 2)
room.corrids.insertLast(circleStart);
@circleStart = null;
circleCnt = 0;
}
}
//Generate systems
for(uint i = 0; i < roomCnt; ++i) {
Room@ room = rooms[i];
//Generate systems
angle = 0.0;
radius = 0.0;
angleStep = twopi;
startAngle = randomd(0.0, twopi);
circle = 0;
int quality = 0;
if(i == 0 && roomCnt > estPlayerCount)
quality = 100;
uint hwInd = randomi(0, sysPerRoom-1);
for(uint n = 0; n < sysPerRoom; ++n) {
//Generate system
vec3d pos = quaterniond_fromAxisAngle(vec3d_up(), angle + startAngle) * vec3d_front(radius);
pos.y = randomd(-sysHeightVar, sysHeightVar);
pos += room.position;
SystemData@ sys = addSystem(pos, quality=quality);
if(i != 0) {
if(hwInd == n)
addPossibleHomeworld(sys);
}
else if(circle == 0) {
auto@ blackHole = getSystemType("CoreBlackhole");
if(blackHole !is null)
sys.systemType = int(blackHole.id);
}
room.systems.insertLast(sys);
room.circles.insertLast(circle);
//Generate links to previous circle
if(circle > 0) {
SystemData@ closest;
double closestDist = INFINITY;
SystemData@ second;
double secondDist = INFINITY;
for(int j = int(n); j >= 0; --j) {
if(room.circles[j] < circle-1)
break;
if(room.circles[j] > circle-1)
continue;
SystemData@ other = room.systems[j];
double d = other.position.distanceToSQ(sys.position);
if(d < closestDist) {
@second = closest;
secondDist = closestDist;
closestDist = d;
@closest = other;
}
else if(d < secondDist) {
@second = other;
secondDist = d;
}
}
if(closest !is null)
addLink(sys, closest);
if(second !is null)
addLink(sys, second);
}
//Proceed to next system position
angle += angleStep;
if(angle + angleStep > twopi) {
angle = 0.0;
radius += spacing;
startAngle = randomd(0.0, twopi);
anglePct = (spacing / (2.0 * pi * radius));
if(sysPerRoom - n - 1 > 0)
angleStep = max(anglePct * twopi, twopi / double(sysPerRoom - n - 1));
circle += 1;
}
}
}
//Generate corridors
for(uint i = 0; i < roomCnt; ++i) {
Room@ room = rooms[i];
for(uint n = 0, ncnt = room.corrids.length; n < ncnt; ++n) {
Room@ other = room.corrids[n];
//Build corridor between rooms
vec3d offset = (other.position - room.position);
double offdist = offset.length;
double spacStep = spacing / offdist;
double corStart = roomRadius * 0.5 / offdist;
double corEnd = 1.0 - corStart;
uint len = clamp(floor((corEnd - corStart) / spacStep), 1, corridorLength);
double corStep = (corEnd - corStart) / double(len);
corStart += corStep * 0.5;
SystemData@ first, last;
for(uint x = 0; x < len; ++x) {
vec3d corPos = room.position + offset * (corStep * x + corStart);
if(room.circle == other.circle)
corPos = corPos.normalized(room.position.length - roomRadius * 0.25);
auto@ sys = addSystem(corPos, quality=200);
if(last !is null)
addLink(last, sys);
@last = sys;
if(x == 0)
@first = last;
}
//Find systems to link to
double dist = INFINITY;
SystemData@ closest;
for(uint j = 0, jcnt = room.systems.length; j < jcnt; ++j) {
double d = room.systems[j].position.distanceToSQ(first.position);
if(d < dist) {
@closest = room.systems[j];
dist = d;
}
}
addLink(closest, first);
dist = INFINITY;
for(uint j = 0, jcnt = other.systems.length; j < jcnt; ++j) {
double d = other.systems[j].position.distanceToSQ(last.position);
if(d < dist) {
@closest = other.systems[j];
dist = d;
}
}
addLink(closest, last);
}
}
}
#section all
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

+125
View File
@@ -0,0 +1,125 @@
#include "include/map.as"
enum MapSetting {
M_SystemCount,
M_SystemSpacing,
M_Flatten,
M_ConnectEnds,
};
class CorkscrewMap : Map {
CorkscrewMap() {
super();
name = locale::CORKSCREW_GALAXY;
description = locale::CORKSCREW_GALAXY_DESC;
color = 0xff5900ff;
icon = "maps/Corkscrew/corkscrew.png";
}
#section client
void makeSettings() {
Number(locale::SYSTEM_COUNT, M_SystemCount, DEFAULT_SYSTEM_COUNT, decimals=0, step=10, min=6, halfWidth=true);
Number(locale::SYSTEM_SPACING, M_SystemSpacing, DEFAULT_SPACING, decimals=0, step=1000, min=MIN_SPACING, halfWidth=true);
Toggle(locale::FLATTEN, M_Flatten, false, halfWidth=true);
Toggle(locale::CONNECT_ENDS, M_ConnectEnds, true, halfWidth=true);
}
#section server
void placeSystems() {
uint systemCount = uint(getSetting(M_SystemCount, DEFAULT_SYSTEM_COUNT));
double spacing = modSpacing(getSetting(M_SystemSpacing, DEFAULT_SPACING));
bool flatten = getSetting(M_Flatten, 0.0) != 0.0;
bool connectEnds = getSetting(M_ConnectEnds, 1.0) != 0.0;
autoGenerateLinks = false;
uint width = max(1, uint(ceil(log(double(systemCount))/log(10.0))));
uint length = ceil(double(systemCount) / double(width));
double startAngle = randomd(0.0, twopi);
double angle = 0.0;
double radius = spacing * 2.0;
double height = 0.0;
double heightDiff = spacing * 0.25;
int xStart = -floor(double(width)/2.0);
int xEnd = ceil(double(width)/2.0);
vec3d pos;
vec3d prevPos = quaterniond_fromAxisAngle(vec3d_up(), startAngle - 0.1) * vec3d_front(radius);
prevPos.y = spacing;
int hwStep, hwOffset;
if(connectEnds) {
hwStep = floor(double(systemCount) / double(max(estPlayerCount, 1)));
hwOffset = (hwStep / 2) + randomi(-width,width);
}
else {
hwStep = floor(double(systemCount) / double(max(estPlayerCount - 1, 1)));
hwOffset = hwStep - 1 + randomi(-width,0);
}
array<SystemData@> cur(width);
array<SystemData@> prev(width);
int count = 0;
for(uint n = 0; n < length; ++n) {
//Make systems in strip
vec3d offset;
for(int x = xStart, i = 0; x < xEnd; ++x) {
pos = quaterniond_fromAxisAngle(vec3d_up(), startAngle + angle) * vec3d_front(radius);
pos.y = height + randomd(-heightDiff, heightDiff);
if(x == xStart)
offset = (pos - prevPos).cross(vec3d_up()).normalized(spacing);
pos += offset * -double(x);
if(flatten)
pos.y = 0;
if(x == 0)
prevPos = pos;
SystemData@ sys = addSystem(pos);
@cur[i] = sys;
++i;
++count;
if((count + hwOffset) % hwStep == 0)
addPossibleHomeworld(sys);
}
//Make links
for(uint i = 0; i < width; ++i) {
if(i != 0)
addLink(cur[i-1], cur[i]);
if(i != width-1)
addLink(cur[i], cur[i+1]);
if(prev[i] !is null)
addLink(prev[i], cur[i]);
}
prev = cur;
//Update next position
double anglePct = (spacing / (2.0 * pi * radius));
angle += anglePct * twopi;
radius += spacing * anglePct * double(width) * 1.5;
height -= spacing * anglePct * 4.0;
if(angle >= twopi)
angle -= twopi;
}
uint genCnt = systemData.length;
//Add final homeworld
if(possibleHomeworlds.length < estPlayerCount)
addPossibleHomeworld(systemData[randomi(genCnt-(width*2), genCnt-1)]);
//Create the wormhole
if(connectEnds) {
createWormhole( systemData[randomi(0, width-1)],
systemData[randomi(genCnt-width, genCnt-1)]);
}
}
#section all
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

+125
View File
@@ -0,0 +1,125 @@
#include "include/map.as"
enum MapSetting {
M_SystemCount,
M_SystemSpacing,
M_Flatten,
M_Mirror,
};
class DumbbellMap : Map {
DumbbellMap() {
super();
name = locale::DUMBBELL_MAP;
description = locale::DUMBBELL_MAP_DESC;
sortIndex = -100;
color = 0xd252ffff;
icon = "maps/Dumbbell/dumbbell.png";
}
#section client
void makeSettings() {
Number(locale::SYSTEM_COUNT, M_SystemCount, DEFAULT_SYSTEM_COUNT, decimals=0, step=10, min=10, halfWidth=true);
Number(locale::SYSTEM_SPACING, M_SystemSpacing, DEFAULT_SPACING, decimals=0, step=1000, min=MIN_SPACING, halfWidth=true);
Toggle(locale::FLATTEN, M_Flatten, false, halfWidth=true);
Toggle(locale::PERFECT_MIRROR, M_Mirror, false, halfWidth=true, tooltip=locale::TT_PERFECT_MIRROR);
}
#section server
void placeSystems() {
uint systemCount = uint(getSetting(M_SystemCount, DEFAULT_SYSTEM_COUNT));
double spacing = modSpacing(getSetting(M_SystemSpacing, DEFAULT_SPACING));
bool flatten = getSetting(M_Flatten, 0.0) != 0.0;
bool mirror = getSetting(M_Mirror, 0.0) != 0.0;
//Calculate values
double bellSystems = ceil(double(systemCount) * 0.43);
double bellRadius = sqrt(bellSystems) * spacing * 0.5;
//Make left bell
genBell(vec3d(0, 0, -bellRadius*3.0), bellRadius, bellSystems);
genCorridor(vec3d(0, 0, -bellRadius*2.0+spacing*0.75), vec3d(0, 0, -spacing), ceil(double(systemCount) * 0.07));
if(!mirror) {
//Make right bell
genBell(vec3d(0, 0, bellRadius*3.0), bellRadius, bellSystems);
genCorridor(vec3d(0, 0, 0), vec3d(0, 0, bellRadius*2.0-spacing*0.75), ceil(double(systemCount) * 0.07));
}
else {
//Create empty systems opposite every generated system
for(uint i = 0, cnt = systemData.length; i < cnt; ++i) {
auto@ other = systemData[i];
vec3d pos = other.position;
pos.z = -pos.z;
auto@ sys = addSystem(pos, mirrorSystem = other);
if(possibleHomeworlds.find(other) != -1)
addPossibleHomeworld(sys);
}
genCorridor(vec3d(0, 0, 0), vec3d(0, 0, 0), ceil(double(systemCount) * 0.07), quality=500);
}
}
void genBell(vec3d around, double radius, uint systemCount) {
double spacing = modSpacing(getSetting(M_SystemSpacing, DEFAULT_SPACING));
bool flatten = getSetting(M_Flatten, 0.0) != 0.0;
Poisson2D gen;
gen.circleRadius = radius;
gen.generate(radius*2.0, radius*2.0, spacing);
SystemData@ centerMost;
double centerDist = INFINITY;
for(uint i = 0, cnt = min(gen.length, systemCount); i < cnt; ++i) {
vec3d pos = around;
vec2d offset = gen[i] - vec2d(radius, radius);
pos.x += offset.x;
pos.z += offset.y;
if(!flatten)
pos.y += randomd(-spacing * 0.3, spacing * 0.3);
auto@ sys = addSystem(pos);
double d = offset.length;
if(d < centerDist) {
@centerMost = sys;
centerDist = d;
}
}
addPossibleHomeworld(centerMost);
}
void genCorridor(vec3d origin, vec3d dest, uint systemWidth, int quality = 0) {
double spacing = modSpacing(getSetting(M_SystemSpacing, DEFAULT_SPACING));
bool flatten = getSetting(M_Flatten, 0.0) != 0.0;
double wstep = 1.0 / ceil(sqrt(double(systemWidth)) / 0.75);
if(origin.distanceTo(dest) < spacing)
wstep = 1.1;
else
wstep = max(wstep, 1.0 / max(floor(dest.distanceTo(origin) / spacing), 1.0));
uint height = ceil(sqrt(double(systemWidth) * 0.75));
double w = 0.0;
while(w <= 1.0) {
vec3d pos = origin + (dest-origin)*w;
pos.x -= randomd(0.8, 1.5) * spacing * (double(height-1)/2);
for(uint n = 0; n < height; ++n) {
vec3d sysPos = pos;
if(!flatten)
sysPos.y += randomd(-spacing * 0.3, spacing * 0.3);
addSystem(sysPos, quality=quality);
pos.x += randomd(0.8, 1.5) * spacing;
}
w += wstep;
}
}
#section all
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

+571
View File
@@ -0,0 +1,571 @@
#include "include/map.as"
#section server
import saving;
import map_loader;
import util.design_designer;
from empire import Creeps;
from game_start import generateNewSystem, SystemGenerateHook;
import object_creation;
import ship_groups;
import map_systems;
import statuses;
from remnant_designs import spawnRemnantFleet, loadRemnantDesigns;
class Room {
vec3d position;
SystemData@ core;
uint circle = 0;
double angle = 0;
array<SystemData@> systems;
array<uint> circles;
array<Room@> corrids;
};
#section all
enum MapSetting {
M_SysCount,
M_SystemSpacing,
M_Flatten,
};
const uint INITIAL_EXPANSE = 3;
const double REMNANT_FACTOR = 2.0;
class ExpanseMap : Map {
ExpanseMap() {
super();
name = locale::EXPANSE_MAP;
description = locale::EXPANSE_MAP_DESC;
sortIndex = -120;
eatsPlayers = true;
color = 0x5273ffff;
icon = "maps/Expanse/expanse.png";
}
#section client
void makeSettings() {
Toggle(locale::FLATTEN, M_Flatten, false, halfWidth=true);
Number(locale::SYSTEM_SPACING, M_SystemSpacing, DEFAULT_SPACING, decimals=0, step=1000, min=MIN_SPACING, halfWidth=true);
Description(locale::EXPANSE_MAP_TEXT, lines=3);
}
#section server
array<Room@> rooms;
void preGenerate() {
Map::preGenerate();
radius *= 3.0;
}
void generateRegions() {
radius /= 3.0;
Map::generateRegions();
}
void placeSystems() {
//Generate remnant homeworld
loadMap("maps/Expanse/coreMap.txt").generate(this);
//Generate base clusters
double spacing = modSpacing(getSetting(M_SystemSpacing, DEFAULT_SPACING));
bool flatten = getSetting(M_Flatten, 0.0) != 0.0;
//Calculate amount of 'rooms'
uint players = estPlayerCount;
if(players == 0)
players = 3;
uint roomCnt = players+1;
uint corridorLength = 2;
uint sysPerRoom = 7;
double roomRadius = spacing * 1.5 * sqrt(double(sysPerRoom)) + spacing;
double roomHeightVar = flatten ? 0.0 : roomRadius * 0.2;
double sysHeightVar = flatten ? 0.0 : spacing * 0.25;
double playerOffset = max(roomRadius / (twopi / double(players)), roomRadius);
//Generate rooms
double angle = 0.0;
double radius = 0.0;
double angleStep = twopi;
double anglePct = 0.0;
double startAngle = randomd(0.0, twopi);
Room@ circleStart;
uint circle = 0;
uint circleCnt = 0;
for(uint i = 0; i < roomCnt; ++i) {
Room room;
room.position = quaterniond_fromAxisAngle(vec3d_up(), angle + startAngle) * vec3d_front(radius);
if(i != 0)
room.position.y = randomd(-roomHeightVar, roomHeightVar);
room.circle = circle;
room.angle = angle + startAngle;
rooms.insertLast(room);
if(i != 0)
room.corrids.insertLast(rooms[0]);
++circleCnt;
//Proceed to next room position
angle += angleStep;
if(angle + angleStep > twopi) {
angle = 0.0;
radius += playerOffset;
startAngle = randomd(0.0, twopi);
angleStep = twopi / max(double(roomCnt - i - 1), 1.0);
circle += 1;
circleCnt = 0;
}
}
//Generate systems
for(uint i = 0; i < roomCnt; ++i) {
Room@ room = rooms[i];
//Generate systems
uint sysCount = sysPerRoom;
angle = 0.0;
radius = i == 0 ? 9000 : 0;
angleStep = twopi;
if(radius != 0) {
anglePct = (spacing / (2.0 * pi * radius));
if(sysCount > 0)
angleStep = max(anglePct * twopi, twopi / double(sysCount));
}
startAngle = randomd(0.0, twopi);
circle = 0;
int quality = 0;
if(i == 0 && roomCnt > estPlayerCount)
quality = 200;
for(uint n = 0; n < sysCount; ++n) {
//Generate system
vec3d pos = quaterniond_fromAxisAngle(vec3d_up(), angle + startAngle) * vec3d_front(radius);
if(!flatten)
pos.y = randomd(-sysHeightVar, sysHeightVar);
pos += room.position;
SystemData@ sys = addSystem(pos, quality=quality);
if(circle == 0 && (i != 0 || roomCnt == estPlayerCount))
addPossibleHomeworld(sys);
sys.assignGroup = i;
room.systems.insertLast(sys);
room.circles.insertLast(circle);
//Generate links to previous circle
if(circle > 0) {
SystemData@ closest;
double closestDist = INFINITY;
SystemData@ second;
double secondDist = INFINITY;
for(int j = int(n); j >= 0; --j) {
if(room.circles[j] < circle-1)
break;
if(room.circles[j] > circle-1)
continue;
SystemData@ other = room.systems[j];
double d = other.position.distanceToSQ(sys.position);
if(d < closestDist) {
@second = closest;
secondDist = closestDist;
closestDist = d;
@closest = other;
}
else if(d < secondDist) {
@second = other;
secondDist = d;
}
}
if(closest !is null)
addLink(sys, closest);
if(second !is null)
addLink(sys, second);
}
//Proceed to next system position
angle += angleStep;
if(angle + angleStep > twopi) {
angle = 0.0;
radius += spacing;
startAngle = randomd(0.0, twopi);
anglePct = (spacing / (2.0 * pi * radius));
if(sysCount - n - 1 > 0)
angleStep = max(anglePct * twopi, twopi / double(sysCount - n - 1));
circle += 1;
}
}
//Make expanse systems
if(i != 0) {
double aStep = min(twopi / double(roomCnt - 1), pi*0.33);
double minAngle = room.angle - aStep * 0.5;
double maxAngle = room.angle + aStep * 0.5;
aStep = (maxAngle - minAngle) / double(INITIAL_EXPANSE);
for(uint n = 0; n < INITIAL_EXPANSE; ++n) {
double ang = minAngle + double(n) * aStep + aStep * 0.5;
double rad = room.position.length + radius;
vec3d pos = quaterniond_fromAxisAngle(vec3d_up(), ang) * vec3d_front(rad);
pos.y = room.position.y;
if(!flatten)
pos.y += randomd(-spacing*0.5, spacing*0.5);
auto@ sys = addSystem(pos);
sys.assignGroup = i;
ExpanseSystem es;
es.index = sys.index;
es.shouldExpand = true;
es.minAngle = minAngle;
es.maxAngle = maxAngle;
es.circle = 0;
es.radius = rad;
es.field = i;
es.position = n;
es.spacing = spacing;
es.flatten = flatten;
trackSystems.insertLast(es);
}
}
}
//Generate corridors
for(uint i = 0; i < roomCnt; ++i) {
Room@ room = rooms[i];
for(uint n = 0, ncnt = room.corrids.length; n < ncnt; ++n) {
Room@ other = room.corrids[n];
//Build corridor between rooms
vec3d offset = (other.position - room.position);
double offdist = offset.length;
double spacStep = spacing / offdist;
double corStart = roomRadius * 0.5 / offdist;
double corEnd = 1.0 - corStart;
uint len = clamp(floor((corEnd - corStart) / spacStep), 1, corridorLength);
double corStep = (corEnd - corStart) / double(len);
corStart += corStep * 0.5;
SystemData@ first, last;
for(uint x = 0; x < len; ++x) {
vec3d corPos = room.position + offset * (corStep * x + corStart);
if(room.circle == other.circle)
corPos = corPos.normalized(room.position.length - roomRadius * 0.25);
auto@ sys = addSystem(corPos, quality=200);
if(last !is null)
addLink(last, sys);
@last = sys;
if(x == 0)
@first = last;
}
//Find systems to link to
double dist = INFINITY;
SystemData@ closest;
for(uint j = 0, jcnt = room.systems.length; j < jcnt; ++j) {
double d = room.systems[j].position.distanceToSQ(first.position);
if(d < dist) {
@closest = room.systems[j];
dist = d;
}
}
addLink(closest, first);
dist = INFINITY;
for(uint j = 0, jcnt = other.systems.length; j < jcnt; ++j) {
double d = other.systems[j].position.distanceToSQ(last.position);
if(d < dist) {
@closest = other.systems[j];
dist = d;
}
}
addLink(closest, last);
}
}
}
void createRemnant(SystemDesc@ system, double size, ExpanseSystem@ es = null) {
int fleetSize = ceil(size / double(es.defenders.length + es.queuedFleets) / 25.0) * 25;
vec3d pos = system.position;
vec2d offset = random2d(500, system.radius*0.85);
pos.x += offset.x;
pos.z += offset.y;
auto@ ship = spawnRemnantFleet(pos, fleetSize, 0.4);
if(es !is null && ship !is null) {
es.defenders.insertLast(ship);
if(es.queuedFleets > 0)
es.queuedFleets--;
}
}
void createRemnants(SystemDesc@ system, double size, ExpanseSystem@ es, bool queued = false) {
es.queuedFleets = max(randomd(pow(size, 0.14), pow(size, 0.24)), 1.0);
if(queued)
return;
while(es.queuedFleets > 0)
createRemnant(system, size, es);
}
void setPlanetsLocked(SystemDesc@ system, bool value) {
auto@ status = getStatusType("BlockedColonization");
uint plCnt = system.object.planetCount;
for(uint i = 0, cnt = plCnt; i < cnt; ++i) {
if(status !is null) {
if(value)
system.object.planets[i].addStatus(status.id);
else
system.object.planets[i].removeStatusInstanceOfType(status.id);
}
else {
system.object.planets[i].setQuarantined(value);
}
}
}
ExpanseSystem@ setExpanseSystem(SystemDesc@ sys, double remnantSize) {
ExpanseSystem es;
@es.system = sys;
es.remnantSize = remnantSize;
es.origin = origin;
createRemnants(sys, remnantSize, es);
setPlanetsLocked(sys, true);
trackSystems.insertLast(es);
return es;
}
array<ExpanseSystem@> trackSystems;
void init() {
for(uint i = 0, cnt = trackSystems.length; i < cnt; ++i) {
auto@ es = trackSystems[i];
es.origin = origin;
@es.system = getSystem(systems[0].index + es.index);
es.remnantSize = 100;
createRemnants(es.system, es.remnantSize, es);
setPlanetsLocked(es.system, true);
}
setExpanseSystem(getSystem(0), randomd(1200, 1800));
for(uint i = 0, cnt = rooms[0].systems.length; i < cnt; ++i) {
auto@ sys = getSystem(systems[0].index + rooms[0].systems[i].index);
setExpanseSystem(sys, randomd(200, 600));
}
}
void tick(double time) {
bool madeFleet = false;
for(uint i = 0, cnt = trackSystems.length; i < cnt; ++i) {
auto@ es = trackSystems[i];
if(es.system is null)
continue;
if(es.queuedFleets > 0) {
if(!madeFleet) {
createRemnant(es.system, es.remnantSize, es);
madeFleet = true;
}
}
else if(es.defended) {
bool defended = false;
for(uint n = 0, ncnt = es.defenders.length; n < ncnt; ++n) {
auto@ defender = es.defenders[n];
if(defender !is null && defender.valid) {
defended = true;
break;
}
}
if(!defended) {
setPlanetsLocked(es.system, false);
es.defended = false;
es.defenders.length = 0;
if(es.shouldExpand)
expandSystem(es);
}
}
}
}
void expandSystem(ExpanseSystem@ es) {
//Reveal the two closest systems in the next ring
for(uint i = 0; i < 2; ++i) {
bool found = false;
for(uint n = 0, ncnt = trackSystems.length; n < ncnt; ++n) {
auto@ other = trackSystems[n];
if(other.field == es.field && other.circle == es.circle+1 && other.position == es.position+i) {
found = true;
break;
}
}
if(found)
continue;
ExpanseSystem new;
new.origin = es.origin;
new.circle = es.circle+1;
new.spacing = es.spacing;
new.position = es.position+i;
new.flatten = es.flatten;
new.field = es.field;
new.minAngle = es.minAngle;
new.maxAngle = es.maxAngle;
new.radius = es.radius + es.spacing;
new.index = generatedSystems.length;
new.shouldExpand = true;
new.remnantSize = es.remnantSize * REMNANT_FACTOR;
double aStep = (new.maxAngle - new.minAngle) / double(INITIAL_EXPANSE + new.circle);
double ang = new.minAngle + double(new.position) * aStep + aStep * 0.5;
vec3d pos = quaterniond_fromAxisAngle(vec3d_up(), ang) * vec3d_front(new.radius) + new.origin;
pos.y = es.system.position.y;
trackSystems.insertLast(new);
SystemIniter hook;
@hook.mp = this;
@hook.es = new;
generateNewSystem(pos, 2000.0, hook);
}
}
void initSystem(ExpanseSystem@ es) {
auto@ desc = es.system;
const SystemType@ sysType;
do {
@sysType = getDistributedSystemType();
}
while(sysType.unique != SU_NonUnique);
SystemData data;
data.index = es.system.index;
data.position = es.system.position;
desc.radius = 250;
sysType.generate(data, es.system);
desc.object.InnerRadius = desc.radius;
desc.object.OuterRadius = desc.radius * 1.5;
desc.object.radius = desc.object.OuterRadius;
desc.radius = desc.object.OuterRadius;
desc.object.getNode().scale = desc.object.radius + 128.0;
desc.object.getNode().rebuildTransform();
postGenerateSystem(data, es.system);
finalizeSystem(data, es.system);
createRemnants(es.system, es.remnantSize * randomd(0.85, 1.15), es, queued=true);
setPlanetsLocked(es.system, true);
}
void save(SaveFile& file) {
uint cnt = trackSystems.length;
file << cnt;
for(uint i = 0; i < cnt; ++i)
file << trackSystems[i];
}
void load(SaveFile& file) {
uint cnt = 0;
file >> cnt;
trackSystems.length = cnt;
for(uint i = 0; i < cnt; ++i) {
@trackSystems[i] = ExpanseSystem();
file >> trackSystems[i];
}
if(file < SV_0107)
loadRemnantDesigns(file);
}
#section all
}
#section server
class SystemIniter : SystemGenerateHook {
ExpanseMap@ mp;
ExpanseSystem@ es;
void call(SystemDesc@ desc) {
@es.system = desc;
mp.initSystem(es);
}
}
class ExpanseSystem : Savable {
uint index = 0;
uint circle = 0;
uint position = 0;
uint field = 0;
SystemDesc@ system;
vec3d origin;
array<Ship@> defenders;
double minAngle = 0, maxAngle = 0;
double radius = 0;
double remnantSize = 0;
double spacing = 6500;
bool defended = true;
bool shouldExpand = false;
bool flatten = false;
uint queuedFleets = 0;
void save(SaveFile& file) {
file << index << circle;
file << position << field;
file << system.index;
uint cnt = defenders.length;
file << cnt;
for(uint i = 0; i < cnt; ++i)
file << defenders[i];
file << minAngle << maxAngle;
file << radius << remnantSize;
file << defended << shouldExpand;
file << spacing << flatten;
file << origin;
file << queuedFleets;
}
void load(SaveFile& file) {
file >> index >> circle;
file >> position >> field;
uint index = 0;
file >> index;
@system = getSystem(index);
uint cnt = 0;
file >> cnt;
defenders.length = cnt;
for(uint i = 0; i < cnt; ++i)
file >> defenders[i];
file >> minAngle >> maxAngle;
file >> radius >> remnantSize;
file >> defended >> shouldExpand;
file >> spacing >> flatten;
file >> origin;
if(file >= SV_0088)
file >> queuedFleets;
}
};
#section all
+44
View File
@@ -0,0 +1,44 @@
System: Orathi
Position: (0, 0, 0)
Homeworld: False
MakeStar(Temperature = 1000, Radius = 200)
ExpandSystem(500)
TriggerRegion(SetSystemAssignGroup(-2))
MakePlanet(AncientCity, Radius = 24, Conditions = False)
Rename(Orathi Prime)
AddPlanetResource(Water)
AddPlanetResource(Grain)
AddPlanetResource(Grain)
AddPlanetResource(Oil)
AddPlanetResource(AncientCity)
SpawnBuilding(Factory, (4, 3))
SpawnBuilding(Factory, (9, 6))
Trigger(DevelopTiles(1000))
AddResource(Money, +2.5)
MakePlanet(RandomLevel:1, Radius = 16, Conditions = False)
AddPlanetResource(Water)
AddPlanetResource(Meat)
MakePlanet(RandomLevel:1, Radius = 16, Conditions = False)
AddPlanetResource(Water)
AddPlanetResource(Fruit)
ExpandSystem(1000)
MakeAsteroid()
MakeAsteroid()
MakeAsteroid()
MakeAsteroid()
MakeAsteroid()
MakeArtifact()
MakeArtifact()
MakeArtifact()
MakeArtifact()
MakeArtifact()
Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

+837
View File
@@ -0,0 +1,837 @@
#priority init 5001
#include "include/map.as"
#section server
import systems;
from game_start import galaxies;
import camps;
from empire import Creeps, Pirates;
import empire_data;
import object_creation;
import research;
import remnant_designs;
import artifacts;
from objects.Artifact import createArtifact;
from achievements import giveAchievement;
import void addModifierToEmpire(Empire@ emp, const string& spec) from "bonus_effects";
#section all
enum MapSetting {
M_SysCount,
M_SystemSpacing,
M_Flatten,
};
const double BASE_STRENGTH = 6000.0;
const double DOUBLE_WAVES = 3.0;
const double HARD_DIFF_MIN = 1.0;
class InvasionMap : Map {
InvasionMap() {
super();
name = locale::INVASION_MAP;
description = locale::INVASION_MAP_DESC;
color = 0xff4eaeff;
icon = "maps/Invasion/invasion.png";
sortIndex = -140;
dlc = "Heralds";
eatsPlayers = true;
isUnique = true;
}
#section client
void makeSettings() {
Toggle(locale::FLATTEN, M_Flatten, false, halfWidth=true);
Number(locale::SYSTEM_SPACING, M_SystemSpacing, DEFAULT_SPACING, decimals=0, step=1000, min=MIN_SPACING, halfWidth=true);
auto@ diff = Dropdown(locale::INV_DIFFICULTY, "INVASION_DIFFICULTY");
diff.addOption(locale::EASY, 0.25);
diff.addOption(locale::NORMAL, 0.5);
diff.addOption(locale::HARD, 1.0);
diff.set(0.5);
Description(locale::INVASION_MAP_TEXT, lines=2);
}
#section server
void modSettings(GameSettings& settings) override {
config::ENABLE_INFLUENCE_VICTORY = 0.0;
settings.setNamed("ENABLE_INFLUENCE_VICTORY", 0.0);
config::ENABLE_DREAD_PIRATE = 0.0;
settings.setNamed("ENABLE_DREAD_PIRATE", 0.0);
}
bool ensureConnectedLinks() override {
return true;
}
void placeSystems() {
double spacing = modSpacing(getSetting(M_SystemSpacing, DEFAULT_SPACING));
bool flatten = getSetting(M_Flatten, 0.0) != 0.0;
uint players = estPlayerCount;
if(players == 0)
players = 3;
double radSize = spacing * 10.0 * double(players+1);
double startDist = (radSize / (2.0 * pi)) + (spacing * 6.0);
double heightDiff = spacing * 0.2;
double radial = twopi / double(players+1);
double startRad = radial / double(players+1);
int edgeType = -1;
auto@ sysType = getSystemType("AncientSystem");
if(sysType !is null)
edgeType = sysType.id;
for(uint i = 0; i < players; ++i) {
PlayerData dat;
playerData.insertLast(dat);
vec3d homePos = quaterniond_fromAxisAngle(vec3d_up(), startRad) * vec3d_front(startDist);
if(!flatten)
homePos.y += randomd(-heightDiff, heightDiff);
//Create the homeworld
auto@ hwSys = addSystem(homePos);
hwSys.assignGroup = i;
addPossibleHomeworld(hwSys);
EndSystem hwEnd;
hwEnd.index = hwSys.index;
@dat.homeworld = hwEnd;
//Create the edge systems
double edgeRad = -0.3 * pi;
for(uint n = 0; n < 3; ++n) {
vec3d edgePos = homePos;
edgePos += quaterniond_fromAxisAngle(vec3d_up(), edgeRad) * homePos.normalized(spacing * 0.6);
auto@ sys = addSystem(edgePos, sysType=edgeType);
sys.assignGroup = i;
addLink(sys, hwSys);
EndSystem es;
es.index = sys.index;
dat.edges.insertLast(es);
edgeRad += 0.3 * pi;
}
//Create the extra layers
for(uint l = 0; l < 5; ++l) {
uint layCnt = 2+l;
double totRad = pi * 0.25 * double(layCnt);
double radStep = totRad / double(layCnt);
double rad = totRad * -0.5 + radStep * 0.5;
double sysDist = spacing * double(l+1);
for(uint n = 0; n < layCnt; ++n) {
vec3d sysPos = homePos;
sysPos -= quaterniond_fromAxisAngle(vec3d_up(), rad) * homePos.normalized(sysDist);
if(!flatten)
sysPos.y += randomd(-heightDiff, heightDiff);
auto@ sys = addSystem(sysPos);
sys.assignGroup = i;
EndSystem es;
es.index = sys.index;
dat.inner.insertLast(es);
rad += radStep;
}
}
startRad += radial + (radial / double(players+1));
}
}
void preInit() {
//Modify creep empire
Pirates.name = locale::REMNANT_DEFENSE_LINE;
Pirates.color = Color(0x4fd07bff);
//Create invasion empire
{
@Invaders = Empire();
Invaders.name = locale::INVADER;
Invaders.color = Color(0xff4040ff);
Invaders.major = false;
Invaders.visionMask = ~0;
auto@ flag = getEmpireFlag(randomi(0, getEmpireFlagCount()-1));
Invaders.flagDef = flag.flagDef;
Invaders.flagID = flag.id;
@Invaders.flag = getMaterial(Creeps.flagDef);
@Invaders.shipset = getShipset("ALL");
}
//Empires are allied with creeps here
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
Empire@ emp = getEmpire(i);
if(!emp.major)
continue;
Pirates.setHostile(emp, false);
emp.setHostile(Pirates, false);
Invaders.setHostile(emp, true);
emp.setHostile(Invaders, true);
emp.modTotalBudget(+500);
}
Pirates.setHostile(Invaders, true);
Invaders.setHostile(Pirates, true);
}
void init() {
if(isLoadedSave)
return;
//See if we should load strengths
loadStrengthList("maps/Invasion/strengths.txt");
//Add the global modifiers
uint majorMask = 0;
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
Empire@ emp = getEmpire(i);
if(!emp.major)
continue;
emp.Victory = -2;
addModifierToEmpire(emp, "StationHull::MaintenanceModFactor(0.0)");
addModifierToEmpire(emp, "StationHull::HPModFactor(0.25)");
addModifierToEmpire(emp, "StationHull::RangeModFactor(0.5)");
addModifierToEmpire(emp, "StationHull::LaborModFactor(2.0)");
addModifierToEmpire(emp, "StationHull::MaintCostFactor(0.0)");
addModifierToEmpire(emp, "MaintCostFactor(0.0)");
majorMask |= emp.mask;
Object@ hw = emp.Homeworld;
if(hw is null)
@hw = emp.HomeObj;
if(hw !is null)
hw.modLaborIncome(+5.0 / 60.0);
}
//YOU WILL SIT IN THE CIRCLE AND SING KUMBAYA DAMNIT
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
Empire@ emp = getEmpire(i);
if(emp.major)
emp.ForcedPeaceMask |= majorMask;
}
//Spawn remnant defenses
const Design@ defStation = Creeps.getDesign("Defense Station");
for(uint i = 0, cnt = playerData.length; i < cnt; ++i) {
auto@ dat = playerData[i];
dat.homeworld.index += systems[0].index;
@dat.homeworld.desc = getSystem(dat.homeworld.index);
for(uint n = 0, ncnt = dat.inner.length; n < ncnt; ++n) {
auto@ sys = dat.inner[n];
sys.index += systems[0].index;
@sys.desc = getSystem(sys.index);
}
for(uint n = 0, ncnt = dat.edges.length; n < ncnt; ++n) {
auto@ sys = dat.edges[n];
sys.index += systems[0].index;
@sys.desc = getSystem(sys.index);
double radius = sys.desc.radius;
//Give everyone vision over this system
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i)
sys.desc.object.grantVision(getEmpire(i));
//Spawn defense stations
vec3d offset = (sys.desc.position - dat.homeworld.desc.position).normalized(radius * 0.75);
auto@ obj = createShip(sys.desc.position + offset, defStation, Pirates, free=true);
obj.orbitDuration(1000000000000.0);
sys.defenses.insertLast(obj);
@obj = createShip(sys.desc.position + quaterniond_fromAxisAngle(vec3d_up(), pi * 0.2) * offset, defStation, Pirates, free=true);
obj.orbitDuration(1000000000000.0);
sys.defenses.insertLast(obj);
@obj = createShip(sys.desc.position + quaterniond_fromAxisAngle(vec3d_up(), -pi * 0.2) * offset, defStation, Pirates, free=true);
obj.orbitDuration(1000000000000.0);
sys.defenses.insertLast(obj);
}
}
}
#section all
};
#section server
class PlayerData : Savable {
Empire@ empire;
EndSystem@ homeworld;
array<EndSystem@> inner;
array<EndSystem@> edges;
uint previousWave = uint(-1);
double stationHealth = 0.0;
double stationEff = 0.0;
void save(SaveFile& file) {
file << homeworld;
file << empire;
file << stationHealth;
file << stationEff;
file << previousWave;
uint cnt = inner.length;
file << cnt;
for(uint i = 0; i < cnt; ++i)
file << inner[i];
cnt = edges.length;
file << cnt;
for(uint i = 0; i < cnt; ++i)
file << edges[i];
}
void load(SaveFile& file) {
@homeworld = EndSystem();
file >> homeworld;
file >> empire;
file >> stationHealth;
file >> stationEff;
if(file >= SV_0156)
file >> previousWave;
uint cnt = 0;
file >> cnt;
inner.length = cnt;
for(uint i = 0; i < cnt; ++i) {
@inner[i] = EndSystem();
file >> inner[i];
}
file >> cnt;
edges.length = cnt;
for(uint i = 0; i < cnt; ++i) {
@edges[i] = EndSystem();
file >> edges[i];
}
}
};
class EndSystem : Savable {
uint index;
SystemDesc@ desc;
array<Ship@> defenses;
array<Ship@> invaders;
bool isFighting = false;
void save(SaveFile& file) {
file << index;
file << isFighting;
uint cnt = defenses.length;
file << cnt;
for(uint i = 0; i < cnt; ++i)
file << defenses[i];
cnt = invaders.length;
file << cnt;
for(uint i = 0; i < cnt; ++i)
file << invaders[i];
}
void load(SaveFile& file) {
file >> index;
file >> isFighting;
uint cnt = 0;
file >> cnt;
defenses.length = cnt;
for(uint i = 0; i < cnt; ++i)
file >> defenses[i];
file >> cnt;
invaders.length = cnt;
for(uint i = 0; i < cnt; ++i)
file >> invaders[i];
}
};
Mutex mtx;
array<PlayerData@> playerData;
Empire@ Invaders;
double symbolicStrength = 0.0;
double waveTimer = 0.0;
array<double> WAVE_STRENGTHS;
void save(SaveFile& file) {
if(hasInvasionMap()) {
file.write1();
file << Invaders;
file << symbolicStrength;
file << waveTimer;
uint cnt = playerData.length;
file << cnt;
for(uint i = 0; i < cnt; ++i)
file << playerData[i];
}
else {
file.write0();
}
}
void loadStrengthList(const string& fname) {
WAVE_STRENGTHS.length = 0;
ReadFile file(fname, true);
while(file++)
WAVE_STRENGTHS.insertLast(toDouble(file.line));
}
void load(SaveFile& file) {
if(file.readBit()) {
file >> Invaders;
file >> symbolicStrength;
file >> waveTimer;
uint cnt = 0;
file >> cnt;
playerData.length = cnt;
for(uint i = 0; i < cnt; ++i) {
@playerData[i] = PlayerData();
file >> playerData[i];
}
}
loadStrengthList("maps/Invasion/strengths.txt");
}
double getInvasionInterval() {
return 3.0 * 60.0;
}
double getInvasionTimer() {
return waveTimer;
}
double getInvasionStrength() {
return symbolicStrength;
}
void increaseInvasionStrength(double amount, bool modify = true) {
if(modify)
amount /= double(playerData.length);
symbolicStrength += amount;
}
bool hasInvasionMap() {
for(uint i = 0, cnt = galaxies.length; i < cnt; ++i) {
if(cast<InvasionMap>(galaxies[i]) !is null)
return true;
}
return false;
}
bool initialized = false;
void tick(double time) {
if(!hasInvasionMap())
return;
if(!initialized && playerEmpire.valid) {
guiDialogueAction(CURRENT_PLAYER, "Invasion.InvasionMap::SetupGUI");
if(!isLoadedSave) {
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
Empire@ emp = getEmpire(i);
if(!emp.major)
continue;
emp.replaceResearchOfType(getTechnologyID("OrbitalConstruction"), getTechnologyID("SupportCap"));
emp.replaceResearchOfType(getTechnologyID("OrbitalConstruction2"), getTechnologyID("Damage"));
}
}
initialized = true;
}
if(time == 0.0 || gameSpeed == 0.0 || gameTime < 0.5)
return;
//Check for losing systems
for(uint i = 0, cnt = playerData.length; i < cnt; ++i) {
auto@ dat = playerData[i];
if(dat.homeworld.desc is null)
@dat.homeworld.desc = getSystem(dat.homeworld.index);
if(dat.empire is null) {
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
Empire@ emp = getEmpire(i);
Region@ homeReg;
if(emp.Homeworld !is null)
@homeReg = emp.Homeworld.region;
else if(emp.HomeObj !is null)
@homeReg = emp.HomeObj.region;
if(homeReg !is null) {
if(dat.homeworld.desc.object is homeReg)
@dat.empire = emp;
}
}
}
for(uint j = 0, jcnt = dat.edges.length; j < jcnt; ++j) {
auto@ sys = dat.edges[j];
if(sys.desc is null)
@sys.desc = getSystem(sys.index);
//Remove lost defenses
for(uint n = 0, ncnt = sys.defenses.length; n < ncnt; ++n) {
if(sys.defenses[n] is null || !sys.defenses[n].valid) {
sys.defenses.removeAt(n);
--n; --ncnt;
}
}
//Replace invaders with pickups
vec3d lastInvader;
for(uint n = 0, ncnt = sys.invaders.length; n < ncnt; ++n) {
auto@ obj = sys.invaders[n];
if(obj !is null && obj.valid)
continue;
if(obj !is null)
lastInvader = obj.position;
sys.invaders.removeAt(n);
--n; --ncnt;
}
if(sys.isFighting && sys.invaders.length == 0) {
sys.isFighting = false;
const ArtifactType@ type;
uint possibs = 0;
for(uint n = 0, ncnt = getArtifactTypeCount(); n < ncnt; ++n) {
auto@ artif = getArtifactType(n);
if(!artif.hasTag("Invasion"))
continue;
possibs += 1;
if(randomd() < 1.0 / double(possibs))
@type = artif;
}
if(type !is null) {
vec3d pos = lastInvader;
if(pos.zero) {
pos = sys.desc.object.position;
vec2d off = random2d(200.0, sys.desc.object.radius * 0.8);
pos.x += off.x;
pos.y += randomd(-20.0, 20.0);
pos.z += off.y;
}
if(symbolicStrength >= 20.0)
giveAchievement(dat.empire, "ACH_INVASION_20");
if(symbolicStrength >= 25.0 && config::INVASION_DIFFICULTY >= HARD_DIFF_MIN)
giveAchievement(dat.empire, "ACH_INVASION_40");
Artifact@ artif = createArtifact(pos, type);
@artif.owner = dat.empire;
}
}
//Remove lost edges
if(sys.defenses.length == 0) {
sys.desc.object.dealStarDamage(1000000000000000000);
sys.desc.object.addSystemDPS(1000000000000000000);
increaseInvasionStrength(2.0);
for(uint i = 0, cnt = sys.desc.object.planetCount; i < cnt; ++i)
sys.desc.object.planets[i].destroyQuiet();
dat.edges.removeAt(j);
--j; --jcnt;
}
}
//Remove lost systems
if(dat.edges.length == 0) {
for(uint j = 0, jcnt = dat.inner.length; j < jcnt; ++j) {
auto@ sys = dat.inner[j];
if(sys.desc is null)
@sys.desc = getSystem(sys.index);
sys.desc.object.dealStarDamage(1000000000000000000);
sys.desc.object.addSystemDPS(1000000000000000000);
for(uint i = 0, cnt = sys.desc.object.planetCount; i < cnt; ++i)
sys.desc.object.planets[i].destroyQuiet();
}
auto@ sys = dat.homeworld;
if(sys !is null) {
if(sys.desc is null)
@sys.desc = getSystem(sys.index);
sys.desc.object.dealStarDamage(1000000000000000000);
sys.desc.object.addSystemDPS(1000000000000000000);
for(uint i = 0, cnt = sys.desc.object.planetCount; i < cnt; ++i)
sys.desc.object.planets[i].destroyQuiet();
}
dat.inner.length = 0;
}
//Remove lost players
if(dat.inner.length == 0) {
playerData.removeAt(i);
--i; --cnt;
}
}
//Increase remnant strength
waveTimer -= time;
if(waveTimer <= 0.0) {
waveTimer += 3.0 * 60.0;
//Update defense station strength
double stHP = -1.0 + 0.5 * pow(1.3, symbolicStrength / DOUBLE_WAVES);
double stDPS = min(-1.0+ 0.2 * pow(1.4, symbolicStrength / DOUBLE_WAVES), 0.0);
for(uint i = 0, cnt = playerData.length; i < cnt; ++i) {
auto@ dat = playerData[i];
for(uint n = 0, ncnt = dat.edges.length; n < ncnt; ++n) {
auto@ edge = dat.edges[n];
for(uint j = 0, jcnt = edge.defenses.length; j < jcnt; ++j) {
edge.defenses[j].modHPFactor(stHP - dat.stationHealth);
edge.defenses[j].modFleetEffectiveness(stDPS - dat.stationEff);
}
}
dat.stationHealth = stHP;
dat.stationEff = stDPS;
}
//Spawn enemies
double targetStrength;
int waveDown = int(floor(symbolicStrength));
int waveUp = int(ceil(symbolicStrength));
if(uint(waveUp) >= WAVE_STRENGTHS.length) {
double finalWave = WAVE_STRENGTHS.length;
double baseStrength = BASE_STRENGTH;
if(WAVE_STRENGTHS.length != 0)
baseStrength = WAVE_STRENGTHS[WAVE_STRENGTHS.length-1];
targetStrength = baseStrength * pow(2.0, double(symbolicStrength - finalWave) / DOUBLE_WAVES);
}
else {
double downStr = WAVE_STRENGTHS[waveDown];
double upStr = WAVE_STRENGTHS[waveUp];
targetStrength = downStr;
if(upStr != downStr && waveDown != waveUp)
targetStrength += (upStr - downStr) * (symbolicStrength - double(waveDown)) / double(waveUp - waveDown);
}
if(config::INVASION_DIFFICULTY > 0)
targetStrength *= config::INVASION_DIFFICULTY;
symbolicStrength += 1.0;
uint fleetCount = 1;
uint maxFleets = ceil(symbolicStrength / 5.0);
while(fleetCount < maxFleets && randomd() < 0.33)
fleetCount += 1;
double fleetStrength = sqr(sqrt(targetStrength) / double(fleetCount));
array<RemnantComposition@> fleets;
for(uint f = 0, fcnt = fleetCount; f < fcnt; ++f) {
auto@ comp = composeRemnantFleet(fleetStrength, 0.2, emp=Invaders);
if(comp is null)
continue;
fleets.insertLast(comp);
}
for(uint i = 0, cnt = playerData.length; i < cnt; ++i) {
auto@ dat = playerData[i];
if(dat.edges.length == 0)
continue;
EndSystem@ sys;
uint checkCount = 0;
for(uint i = 0, cnt = dat.edges.length; i < cnt; ++i) {
auto@ edge = dat.edges[i];
if(cnt != 1 && edge.index == dat.previousWave)
continue;
checkCount += 1;
if(randomd() < 1.0 / double(checkCount))
@sys = edge;
}
sys.isFighting = true;
for(uint f = 0, fcnt = fleets.length; f < fcnt; ++f) {
vec3d pos = (sys.desc.position - dat.homeworld.desc.position).normalized();
pos = quaterniond_fromAxisAngle(vec3d_up(), randomd(-0.2, 0.2)*pi) * pos;
vec3d spawnPos = pos * sys.desc.object.radius * 0.95;
spawnPos += sys.desc.position;
Ship@ invader = spawnRemnantFleet(spawnPos, fleets[f], emp=Invaders, alwaysVisible=true);
sys.invaders.insertLast(invader);
if(f == 0 && dat.empire !is null && dat.empire.player !is null)
showPing(dat.empire.player, Invaders, spawnPos, 2);
}
dat.previousWave = sys.index;
}
}
}
bool sendPeriodic(Message& msg) {
if(!hasInvasionMap())
return false;
msg << symbolicStrength;
msg << waveTimer;
return true;
}
#section shadow
from game_start import galaxies;
double symbolicStrength = 0.0;
double waveTimer = 0.0;
void recvPeriodic(Message& msg) {
msg >> symbolicStrength;
msg >> waveTimer;
}
bool hasInvasionMap() {
for(uint i = 0, cnt = galaxies.length; i < cnt; ++i) {
if(cast<InvasionMap>(galaxies[i]) !is null)
return true;
}
return false;
}
double getInvasionInterval() {
return 3.0 * 60.0;
}
double getInvasionTimer() {
return waveTimer;
}
double getInvasionStrength() {
return symbolicStrength;
}
bool initialized = false;
void tick(double time) {
if(!hasInvasionMap())
return;
if(!initialized && playerEmpire.valid) {
guiDialogueAction("Invasion.InvasionMap::SetupGUI");
initialized = true;
}
}
#section gui
import dialogue;
import elements.BaseGuiElement;
import elements.GuiText;
import elements.GuiMarkupText;
import elements.GuiProgressbar;
import util.formatting;
import tabs.tabbar;
class InvasionUI : BaseGuiElement {
GuiText@ waveLabel;
GuiProgressbar@ bar;
GuiText@ strengthLabel;
GuiText@ strength;
InvasionUI() {
super(null, Alignment(Left+0.5f-200, Top+TAB_HEIGHT+GLOBAL_BAR_HEIGHT+1, Width=400, Height=40));
@waveLabel = GuiText(this, Alignment(Left+8, Top+4, Left+90, Bottom-4), locale::NEXT_WAVE);
waveLabel.color = Color(0xaaaaaaff);
@bar = GuiProgressbar(this, Alignment(Left+90, Top+8, Left+250, Bottom-8));
bar.frontColor = Color(0xff8080ff);
bar.font = FT_Small;
bar.strokeColor = colors::Black;
@strengthLabel = GuiText(this, Alignment(Left+270, Top+4, Left+330, Bottom-4), locale::NEXT_STRENGTH);
strengthLabel.color = Color(0xaaaaaaff);
@strength = GuiText(this, Alignment(Left+330, Top+6, Left+392, Bottom-4));
strength.horizAlign = 0.5;
strength.color = Color(0xff4040ff);
strength.font = FT_Bold;
updateAbsolutePosition();
}
void tick(double time) {
visible = ActiveTab.category == TC_Galaxy;
double timer = getInvasionTimer();
double interval = getInvasionInterval();
double str = getInvasionStrength();
strength.text = standardize(str, true);
bar.text = formatTime(timer);
bar.progress = 1.f - (timer / interval);
}
void draw() {
skin.draw(SS_PlainOverlay, SF_Normal, AbsolutePosition.padded(0,-2,0,0));
BaseGuiElement::draw();
}
};
class SetupGUI : DialogueAction {
void call() {
@ui = InvasionUI();
}
}
InvasionUI@ ui;
void tick(double time) {
if(ui !is null)
ui.tick(time);
}
void preReload(Message& msg) {
msg.writeBit(ui !is null);
if(ui !is null)
ui.remove();
}
void postReload(Message& msg) {
if(msg.readBit())
@ui = InvasionUI();
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 418 KiB

+25
View File
@@ -0,0 +1,25 @@
1000
2000
4000
6000
12000
16000
30000
35000
45000
55000
70000
120000
120000
120000
350000
350000
375000
750000
750000
1000000
1000000
1200000
1500000
2000000
2500000
+122
View File
@@ -0,0 +1,122 @@
#priority init 1501
import maps;
#section game
import dialogue;
#section all
ModEditor _map;
class ModEditor : Map {
ModEditor() {
super();
isListed = false;
isScenario = true;
}
#section server
void prepareSystem(SystemData@ data, SystemDesc@ desc) {
@data.homeworlds = null;
Map::prepareSystem(data, desc);
}
bool canHaveHomeworld(SystemData@ data, Empire@ emp) {
return false;
}
void preGenerate() {
Map::preGenerate();
radius = 40000;
}
void placeSystems() {
addSystem(vec3d(0, 0, 0), code=SystemCode()
<< "NameSystem(Sandbox)"
<< "MakeStar(Temperature = 5778, Radius = 75)"
<< "ExpandSystem(2000)"
);
}
void modSettings(GameSettings& settings) {
settings.empires.length = 2;
settings.empires[0].name = "Player";
settings.empires[1].name = "Enemy";
settings.empires[1].shipset = "Gevron";
settings.empires[1].type = ET_NoAI;
config::ENABLE_UNIQUE_SPREADS = 0.0;
config::DISABLE_STARTING_FLEETS = 1.0;
config::ENABLE_DREAD_PIRATE = 0.0;
config::ENABLE_INFLUENCE_EVENTS = 0.0;
}
void init() {
Empire@ player = getEmpire(0);
Empire@ enemy = getEmpire(1);
player.Victory = -2;
enemy.Victory = -2;
}
bool initialized = false;
void tick(double time) {
if(!initialized) {
guiDialogueAction(CURRENT_PLAYER, "ModEditor.ModEditor::SetupGUI");
initialized = true;
}
}
#section all
};
#section gui
import tabs.tabbar;
import tabs.HomeTab;
import editor.editor;
import editor.modinfo;
import editor.overview;
from tabs.GlobalBar import GlobalBar;
from tabs.WikiTab import createWikiTab;
class SetupGUI : DialogueAction {
void call() {
isEditor = true;
//Clean global bar
auto@ gbar = cast<GlobalBar>(globalBar);
gbar.container.visible = false;
//Remove existing tabs
tabBar.goButton.visible = false;
tabBar.homeButton.visible = false;
for(uint i = 1, cnt = tabs.length; i < cnt; ++i)
closeTab(tabs[1]);
auto@ infoTab = createModInfoTab();
infoTab.locked = true;
newTab(infoTab);
switchToTab(infoTab);
auto@ overviewTab = createOverviewTab();
overviewTab.locked = true;
newTab(overviewTab);
auto@ wikiTab = createWikiTab("Modding");
wikiTab.locked = true;
newTab(wikiTab);
closeTab(tabs[0]);
}
};
bool isEditor = false;
void tick(double time) {
if(!isEditor)
return;
//Make any home tabs into overview tabs
for(uint i = 0, cnt = tabs.length; i < cnt; ++i) {
auto@ tab = tabs[i];
if(cast<HomeTab>(tab) !is null)
browseTab(tab, createOverviewTab());
}
}
+87
View File
@@ -0,0 +1,87 @@
#include "include/map.as"
#section server
import util.map_util;
#section all
enum MapSetting {
M_SystemCount,
M_SystemSpacing,
M_Flatten,
};
class RingsMap : Map {
RingsMap() {
super();
name = locale::RINGS_MAP;
description = locale::RINGS_MAP_DESC;
dlc = "Heralds";
sortIndex = -110;
color = 0xffd73cff;
icon = "maps/Rings/rings.png";
}
#section client
void makeSettings() {
Number(locale::SYSTEM_COUNT, M_SystemCount, DEFAULT_SYSTEM_COUNT, decimals=0, step=10, min=6, halfWidth=true);
Number(locale::SYSTEM_SPACING, M_SystemSpacing, DEFAULT_SPACING, decimals=0, step=1000, min=MIN_SPACING, halfWidth=true);
Toggle(locale::FLATTEN, M_Flatten, false, halfWidth=true);
}
#section server
void placeSystems() {
RegionMap regionGroup;
uint systemCount = uint(getSetting(M_SystemCount, DEFAULT_SYSTEM_COUNT));
double spacing = modSpacing(getSetting(M_SystemSpacing, DEFAULT_SPACING));
bool flatten = getSetting(M_Flatten, 0.0) != 0.0;
uint ringCount = max(floor(pow(double(systemCount), 0.33)), 1.0);
uint sysPerRing = ceil(double(systemCount) / double(ringCount));
double baseRadius = (sysPerRing * spacing * 1.2) / twopi;
vec3d ringPos;
double ringRadius;
vec3d ringAxis = vec3d_up();
for(uint i = 0; i < ringCount; ++i) {
if(i == 0) {
ringPos = vec3d(0.0, 0.0, 0.0);
ringRadius = randomd(0.9, 1.5) * baseRadius;
}
else {
//Start somewhere random on the previous ring
ringPos += quaterniond_fromAxisAngle(ringAxis, randomd(0, twopi)) * vec3d(ringRadius, 0.0, 0.0);
ringRadius = randomd(0.9, 1.5) * baseRadius;
if(!flatten)
ringAxis = quaterniond_fromAxisAngle(vec3d_right(), randomd(-0.2*pi, 0.2*pi)) * quaterniond_fromAxisAngle(vec3d_front(), randomd(-0.2*pi, 0.2*pi)) * vec3d_up();
}
double angleStep = twopi / double(sysPerRing);
double angle = randomd(0, angleStep);
for(uint n = 0; n < sysPerRing; ++n) {
vec3d sysPos = ringPos;
sysPos += quaterniond_fromAxisAngle(ringAxis, angle) * vec3d(ringRadius, 0.0, 0.0);
vec3d flatPos = sysPos;
flatPos.y = 0;
if(regionGroup.findRegion(flatPos) !is null) {
angle += angleStep;
continue;
}
auto@ sys = addSystem(sysPos);
regionGroup.addSystem(flatPos, spacing * 0.8);
angle += angleStep;
}
}
move(vec3d() - getAveragePosition());
}
#section all
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 399 KiB

+624
View File
@@ -0,0 +1,624 @@
#priority init 1501
import maps;
#section game
import dialogue;
#section all
#section server
import object_creation;
import systems;
import ship_groups;
import warandpeace;
import influence_global;
from cheats import setCheatsEnabled;
#section shadow
import systems;
#section all
const string SHIPSET = "ALL";
const string FOLDER = modProfile["designs"];
//const string FOLDER = "data/designs/pirates";
const bool OBSOLETE_DEFAULT = false;
const bool ENABLE_DISABLED = false;
Sandbox _map;
class Sandbox : Map {
Sandbox() {
super();
isListed = false;
isScenario = true;
}
#section server
void prepareSystem(SystemData@ data, SystemDesc@ desc) {
@data.homeworlds = null;
Map::prepareSystem(data, desc);
}
bool canHaveHomeworld(SystemData@ data, Empire@ emp) {
return false;
}
void preGenerate() {
Map::preGenerate();
radius = 40000;
}
void placeSystems() {
//Enemy gate system (Odatak)
addSystem(vec3d(0, 0, 0), code=SystemCode()
<< "NameSystem(Sandbox)"
<< "MakeStar(Temperature = 5778, Radius = 75)"
<< "ExpandSystem(2000)"
);
}
void modSettings(GameSettings& settings) {
settings.empires.length = 2;
settings.empires[0].name = "Player";
settings.empires[0].shipset = SHIPSET;
settings.empires[1].name = "Enemy";
settings.empires[1].shipset = "Gevron";
settings.empires[1].type = ET_NoAI;
config::ENABLE_UNIQUE_SPREADS = 0.0;
config::DISABLE_STARTING_FLEETS = 1.0;
config::ENABLE_DREAD_PIRATE = 0.0;
config::ENABLE_INFLUENCE_EVENTS = 0.0;
config::START_EXPLORED_MAP = 1.0;
}
void init() {
Region@ system = getSystem(0).object;
Empire@ player = getEmpire(0);
Empire@ enemy = getEmpire(1);
@player.shipset = getShipset(SHIPSET);
player.Victory = -2;
enemy.Victory = -2;
player.modFTLCapacity(+1000000);
enemy.modFTLCapacity(+1000000);
player.modEnergyStored(+100000);
enemy.modEnergyStored(+100000);
player.modEnergyIncome(+500);
enemy.modEnergyIncome(+500);
player.setHostile(enemy, true);
enemy.setHostile(player, true);
player.ContactMask = int(~0);
enemy.ContactMask = int(~0);
player.visionMask |= enemy.mask;
enemy.visionMask |= player.mask;
system.grantVision(player);
system.grantVision(enemy);
for(uint i = 0, cnt = getSubsystemDefCount(); i < cnt; ++i) {
auto@ def = getSubsystemDef(i);
if(ENABLE_DISABLED || !def.hasTag("Disabled")) {
if(def.hasTag("HeraldsDLC") && !hasDLC("Heralds"))
continue;
player.setUnlocked(def, true);
enemy.setUnlocked(def, true);
for(uint n = 0, ncnt = def.moduleCount; n < ncnt; ++n) {
auto@ mod = def.modules[n];
if(mod.hasTag("Disabled"))
continue;
if(mod.hasTag("HeraldsDLC") && !hasDLC("Heralds"))
continue;
player.setUnlocked(def, mod, true);
enemy.setUnlocked(def, mod, true);
}
}
}
setCheatsEnabled(HOST_PLAYER, true);
}
int empTickIndex = 0;
bool initialized = false;
array<GroupData> groups;
void tick(double time) {
Region@ system = getSystem(0).object;
Empire@ player = getEmpire(0);
Empire@ enemy = getEmpire(1);
if(!initialized) {
guiDialogueAction(CURRENT_PLAYER, "Sandbox.Sandbox::SetupGUI");
initialized = true;
}
int money = INT_MAX>>1;
{
int i = (empTickIndex++) % 2;
Empire@ emp = getEmpire(i);
//Make sure we have lodsamone
if(emp.RemainingBudget < money/2)
emp.addBonusBudget(money);
if(emp.FTLStored < 500000)
emp.modFTLStored(+500000);
//Automatically spawn any ordered support ships on fleets
uint SPAWN_LIMIT = 10;
for(uint i = 0, cnt = emp.fleetCount; i < cnt && SPAWN_LIMIT > 0; ++i) {
Ship@ fleet = cast<Ship>(emp.fleets[i]);
if(fleet is null)
continue;
if(!fleet.hasOrderedSupports)
continue;
groups.syncFrom(fleet.getSupportGroups());
for(uint n = 0, ncnt = groups.length; n < ncnt; ++n) {
auto@ grp = groups[n];
while(grp.ordered > 0 && SPAWN_LIMIT > 0) {
Ship@ ship = createShip(fleet.position, grp.dsg, fleet.owner, groupLeader=null, free=true);
fleet.supportBuildFinished(0, grp.dsg, null, ship);
--grp.ordered;
--SPAWN_LIMIT;
}
}
}
if(emp.player !is null) {
emp.player.controlMask |= player.mask | enemy.mask;
emp.player.viewMask |= player.mask | enemy.mask;
}
}
//Make sure we always accept peace
Lock lck(influenceLock);
for(uint i = 0, cnt = activeTreaties.length; i < cnt; ++i) {
if(activeTreaties[i].inviteMask & enemy.mask != 0)
joinTreaty(enemy, activeTreaties[i].id);
}
}
#section shadow
bool initialized = false;
void tick(double time) {
Region@ system = getSystem(0).object;
Empire@ player = getEmpire(0);
Empire@ enemy = getEmpire(1);
if(!initialized && playerEmpire.valid) {
CURRENT_PLAYER.controlMask |= player.mask | enemy.mask;
CURRENT_PLAYER.viewMask |= player.mask | enemy.mask;
guiDialogueAction("Sandbox.Sandbox::SetupGUI");
initialized = true;
}
}
#section all
};
#section gui
from tabs.tabbar import tabBar, globalBar, closeTab, tabs, newTab, ActiveTab, browseTab;
from tabs.DesignOverviewTab import createDesignOverviewTab, DesignOverview;
from tabs.DesignEditorTab import DesignEditor;
from tabs.GlobalBar import GlobalBar;
from tabs.GalaxyTab import GalaxyTab;
from tabs.HomeTab import HomeTab;
from community.Home import createCommunityHome;
import elements.BaseGuiElement;
import elements.GuiButton;
import elements.GuiDropdown;
import elements.GuiListbox;
import elements.GuiSprite;
import elements.GuiMarkupText;
import elements.GuiContextMenu;
import dialogs.QuestionDialog;
import util.design_export;
from targeting.PointTarget import PointTargeting, targetPoint;
import icons;
uint LastExportedDesign = 0;
dictionary designFileNames;
class SetupGUI : DialogueAction {
void call() {
isSandbox = true;
//Global bar
auto@ gbar = cast<GlobalBar>(globalBar);
gbar.container.visible = false;
@ui = SandboxUI(gbar);
//Tab bar
tabBar.goButton.visible = false;
tabBar.homeButton.visible = false;
for(uint i = 1, cnt = tabs.length; i < cnt; ++i)
closeTab(tabs[1]);
tabs[0].locked = true;
//Quickbar
auto@ gtab = cast<GalaxyTab>(tabs[0]);
gtab.quickbar.visible = false;
//Obsolete old designs
if(OBSOLETE_DEFAULT) {
for(uint i = 0, cnt = playerEmpire.designCount; i < cnt; ++i) {
auto@ dsg = playerEmpire.designs[i];
dsg.setObsolete(true);
obsoletedDesigns.insert(dsg.id);
}
}
//Import designs
FileList list(FOLDER, "*.design", true);
uint cnt = list.length;
for(uint i = 0; i < cnt; ++i) {
DesignDescriptor desc;
read_design(list.path[i], desc);
string fname = list.basename[i];
fname = fname.substr(0, fname.length - list.extension[i].length - 1);
designFileNames.set(desc.name, fname);
if(desc.hull is null)
continue;
if(!playerEmpire.shipset.hasHull(desc.hull))
@desc.hull = getBestHull(desc, getHullTypeTag(desc.hull));
const Design@ newDesign = makeDesign(desc);
if(newDesign is null)
continue;
if(desc.settings !is null)
newDesign.setSettings(desc.settings);
const DesignClass@ cls = playerEmpire.getDesignClass(desc.className);
const Design@ orig = playerEmpire.getDesign(desc.name);
if(orig !is null)
playerEmpire.changeDesign(orig, newDesign, cls);
else
playerEmpire.addDesign(cls, newDesign);
}
LastExportedDesign = playerEmpire.designCount;
//Designs tabs
newTab(createDesignOverviewTab());
newTab(createCommunityHome());
tabs[2].locked = true;
}
};
class FlagshipElement : GuiMarkupContextOption {
const Design@ dsg;
Empire@ forEmpire;
FlagshipElement(const Design@ dsg, Empire@ emp) {
@this.dsg = dsg;
@this.forEmpire = emp;
super(format("[offset=10][color=$5][b]$2[/b][/color] [offset=260]([loc=SIZE/] $3)[/offset][/offset]",
toString(dsg.color),
dsg.name,
standardize(dsg.size, true),
getSpriteDesc(dsg.icon),
toString(dsg.color.interpolate(colors::White, 0.5))),
FT_Subtitle);
icon = dsg.icon;
icon.color = dsg.color;
}
void call(GuiContextMenu@ menu) {
targetPoint(FlagshipTarget(dsg, forEmpire));
}
int opCmp(const GuiListElement@ other) const {
auto@ cmp = cast<const FlagshipElement@>(other);
if(cmp.dsg.size < dsg.size)
return 1;
if(cmp.dsg.size > dsg.size)
return -1;
return 0;
}
};
class FlagshipTarget : PointTargeting {
const Design@ dsg;
Empire@ emp;
FlagshipTarget(const Design@ dsg, Empire@ emp) {
@this.dsg = dsg;
@this.emp = emp;
icon = dsg.icon;
allowMultiple = true;
}
string message(const vec3d& pos, bool valid) {
return dsg.name;
}
void call(const vec3d& pos) {
cheatSpawnFlagship(pos, dsg, emp);
}
Color get_color() {
return emp.color;
}
};
class ConfirmClear : QuestionDialogCallback {
void questionCallback(QuestionDialog@ dialog, int answer) {
if(answer == QA_Yes) {
for(uint i = 0; i < 2; ++i) {
Empire@ emp = getEmpire(i);
uint objCnt = emp.objectCount;
for(uint n = 0; n < objCnt; ++n)
cheatDestroy(emp.objects[n]);
}
}
}
};
const string str_Support = "Support";
class RootText : GuiText {
RootText(IGuiElement@ ParentElement, Alignment@ Align, const string& Txt, FontType font = FT_Normal) {
super(ParentElement, Align, Txt, font);
}
IGuiElement@ elementFromPosition(const vec2i& pos) {
return null;
}
};
class SandboxUI : BaseGuiElement {
GuiText@ myStr;
GuiText@ vsLabel;
GuiText@ theirStr;
GuiButton@ warToggle;
GuiSprite@ warIcon;
GuiSprite@ peaceIcon;
GuiSprite@ warArrow;
GuiText@ warText;
GuiButton@ allyButton;
GuiButton@ enemyButton;
GuiButton@ clearButton;
GuiText@ descText;
SandboxUI(IGuiElement@ parent) {
super(parent, Alignment().fill());
@myStr = GuiText(this, Alignment(Left+4, Top+4, Left+204, Bottom-5));
myStr.color = getEmpire(0).color;
myStr.vertAlign = 0.0;
@vsLabel = GuiText(this, Alignment(Left+4, Top+3, Left+204, Bottom-5), locale::VS);
vsLabel.color = Color(0xaaaaaaff);
vsLabel.vertAlign = 0.5;
vsLabel.horizAlign = 0.5;
@theirStr = GuiText(this, Alignment(Left+4, Top+3, Left+204, Bottom-4));
theirStr.color = getEmpire(1).color;
theirStr.vertAlign = 0.9;
theirStr.horizAlign = 1.0;
@warToggle = GuiButton(this, Alignment(Right-204, Top+3, Right-4, Bottom-5));
@warIcon = GuiSprite(warToggle, recti(), Sprite(material::StatusWar));
@peaceIcon = GuiSprite(warToggle, recti(), Sprite(material::StatusPeace));
@warArrow = GuiSprite(warToggle, recti_area(84,16, 32,32), Sprite(spritesheet::ContextIcons, 0));
@warText = GuiText(warToggle, Alignment().padded(4));
warText.stroke = Color(0x00000080);
warText.font = FT_Bold;
warText.vertAlign = 0.2;
warText.horizAlign = 0.5;
Empire@ otherEmp = playerEmpire is getEmpire(0) ? getEmpire(1) : getEmpire(0);
int w = 160;
@allyButton = GuiButton(this, Alignment(Left+0.5f-w-w/2-6, Top+5, Left+0.5f-w/2-6, Bottom-5));
allyButton.text = locale::SPAWN_ALLIED;
allyButton.color = colors::Green;
allyButton.buttonIcon = Sprite(spritesheet::ShipIcons, 1, playerEmpire.color);
@enemyButton = GuiButton(this, Alignment(Left+0.5f-w/2, Top+5, Left+0.5f+w/2, Bottom-5));
enemyButton.text = locale::SPAWN_ENEMY;
enemyButton.color = colors::Red;
enemyButton.buttonIcon = Sprite(spritesheet::ShipIcons, 1, otherEmp.color);
@clearButton = GuiButton(this, Alignment(Left+0.5f+w/2+6, Top+5, Left+0.5f+w+w/2+6, Bottom-5));
clearButton.text = locale::SANDBOX_CLEAR;
clearButton.color = colors::Orange;
clearButton.buttonIcon = icons::Close;
@descText = RootText(this, Alignment(Left+250, Bottom+4, Right-4, Bottom+74), locale::SANDBOX_DESC);
descText.noClip = true;
descText.font = FT_Bold;
descText.color = Color(0xaaaaaaff);
descText.stroke = colors::Black;
descText.horizAlign = 1.0;
updateAbsolutePosition();
}
void openContext(Empire@ forEmp) {
GuiContextMenu menu(mousePos);
menu.itemHeight = 36;
menu.flexWidth = false;
menu.width = 400;
uint cnt = playerEmpire.designCount;
for(uint i = 0; i < cnt; ++i) {
auto@ dsg = playerEmpire.designs[i];
if(dsg.obsolete || dsg.newer !is null || dsg.updated !is null)
continue;
if(dsg.hull.hasTag(str_Support))
continue;
menu.addOption(FlagshipElement(dsg, forEmp));
}
menu.list.sortDesc();
menu.updateAbsolutePosition();
}
void update() {
double str = getEmpire(0).TotalMilitary;
double enemyStr = getEmpire(1).TotalMilitary;
myStr.text = format("$1 $2",
standardize(sqr(str) * 0.001, true),
locale::STRENGTH);
theirStr.text = format("$1 $2",
standardize(sqr(enemyStr) * 0.001, true),
locale::STRENGTH);
if(str > enemyStr) {
myStr.font = FT_Bold;
theirStr.font = FT_Normal;
}
else if(enemyStr > str) {
myStr.font = FT_Normal;
theirStr.font = FT_Bold;
}
else {
myStr.font = FT_Normal;
theirStr.font = FT_Normal;
}
}
double timer = 0.0;
void tick(double time) {
bool atWar = getEmpire(0).isHostile(getEmpire(1));
if(atWar) {
warText.text = locale::SANDBOX_WAR;
warText.color = Color(0xff8080ff);
warToggle.color = Color(0xff8080ff);
warArrow.desc = Sprite(spritesheet::ContextIcons, 0);
warIcon.rect = recti_area(6,4, 36,36);
peaceIcon.rect = recti_area(174,20, 20,20);
}
else {
warText.text = locale::SANDBOX_PEACE;
warText.color = Color(0x80ff80ff);
warToggle.color = Color(0x80ff80ff);
warArrow.desc = Sprite(spritesheet::ContextIcons, 2);
peaceIcon.rect = recti_area(158,4, 36,36);
warIcon.rect = recti_area(6,20, 20,20);
}
timer += time;
if(timer >= 0.5) {
update();
timer = 0.0;
}
descText.visible = cast<GalaxyTab>(ActiveTab) !is null;
}
bool onGuiEvent(const GuiEvent& evt) override {
if(evt.type == GUI_Clicked) {
Empire@ otherEmp = playerEmpire is getEmpire(0) ? getEmpire(1) : getEmpire(0);
if(evt.caller is warToggle) {
if(playerEmpire.isHostile(otherEmp))
sendPeaceOffer(otherEmp);
else
declareWar(otherEmp);
return true;
}
if(evt.caller is allyButton) {
openContext(playerEmpire);
return true;
}
if(evt.caller is enemyButton) {
openContext(otherEmp);
return true;
}
if(evt.caller is clearButton) {
question(locale::SANDBOX_CONFIRM_CLEAR, ConfirmClear());
return true;
}
}
return BaseGuiElement::onGuiEvent(evt);
}
};
SandboxUI@ ui;
bool isSandbox = false;
set_int obsoletedDesigns;
void deleteDesign(const Design@ design) {
string fname;
if(!designFileNames.get(design.name, fname))
fname = design.name;
string path = FOLDER+"/"+fname+".design";
if(fileExists(path))
deleteFile(path);
}
void exportDesign(const Design@ design) {
string fname;
if(!designFileNames.get(design.name, fname))
fname = design.name;
write_design(design, FOLDER+"/"+fname+".design", design.cls);
}
void tick(double time) {
if(!isSandbox)
return;
//Make any home tabs into galaxy tabs
for(uint i = 0, cnt = tabs.length; i < cnt; ++i) {
auto@ tab = tabs[i];
if(cast<HomeTab>(tab) !is null) {
browseTab(tab, createDesignOverviewTab());
}
}
//Update UI
if(ui !is null)
ui.tick(time);
//Export any designs we have
for(uint i = 0, cnt = playerEmpire.designCount; i < cnt; ++i) {
auto@ dsg = playerEmpire.designs[i];
if(dsg.updated !is null)
continue;
if(dsg.newer !is null) {
if(!obsoletedDesigns.contains(dsg.id) && dsg.newer.name != dsg.name) {
auto@ check = playerEmpire.getDesign(dsg.name);
if(check is null || check.newer !is null || check.obsolete) {
//Act as obsolete
deleteDesign(dsg);
obsoletedDesigns.insert(dsg.id);
}
}
continue;
}
if(dsg.obsolete) {
//Delete obsoleted designs
if(!obsoletedDesigns.contains(dsg.id)) {
deleteDesign(dsg);
obsoletedDesigns.insert(dsg.id);
}
}
else {
//Export new designs
if(i >= LastExportedDesign) {
exportDesign(dsg);
}
//Re-export unobsoleted designs
if(obsoletedDesigns.contains(dsg.id)) {
exportDesign(dsg);
obsoletedDesigns.erase(dsg.id);
}
}
}
LastExportedDesign = playerEmpire.designCount;
}
#section all
+201
View File
@@ -0,0 +1,201 @@
#include "include/map.as"
enum MapSetting {
M_SystemCount,
M_SystemSpacing,
M_Flatten,
};
#section server
final class SpiralArm {
double angle = 0;
array<SystemData@> systems;
uint sysCount = 0;
array<uint> homeworlds;
};
#section all
class SpiralMap : Map {
SpiralMap() {
super();
name = locale::SPIRAL_GALAXY;
description = locale::SPIRAL_GALAXY_DESC;
color = 0x00e9ffff;
icon = "maps/Spiral/spiral.png";
sortIndex = 1000;
}
#section client
void makeSettings() {
Number(locale::SYSTEM_COUNT, M_SystemCount, DEFAULT_SYSTEM_COUNT, decimals=0, step=10, min=4, halfWidth=true);
Number(locale::SYSTEM_SPACING, M_SystemSpacing, DEFAULT_SPACING, decimals=0, step=1000, min=MIN_SPACING, halfWidth=true);
Toggle(locale::FLATTEN, M_Flatten, false);
}
#section server
void placeSystems() {
uint players = estPlayerCount;
if(players == 0)
players = 1;
const uint armCount = max(min(players, 6), 3);
const uint systemCount = max(uint(getSetting(M_SystemCount, DEFAULT_SYSTEM_COUNT)), armCount + 1);
bool flatten = getSetting(M_Flatten, 0.0) != 0.0;
uint coreSystems = max(systemCount / 4, 1);
uint perArm = (systemCount - coreSystems) / armCount;
coreSystems = systemCount - (perArm * armCount);
double systemSpacing = modSpacing(getSetting(M_SystemSpacing, DEFAULT_SPACING));
const double coreHeightVariation = flatten ? 0.0 : 1000.0;
const double heightVariation = flatten ? 0.0 : 600.0;
const double spiralBase = systemSpacing * double(systemCount) / 75.0;
const double spiralCurve = 0.5;
int coreSysType = -1;
if(systemCount > 50) {
auto@ bh = getSystemType("CoreBlackhole");
if(bh !is null)
coreSysType = bh.id;
}
addSystem(vec3d(), 500, false, coreSysType);
coreSystems -= 1;
double coreRingDist = 0.0;
//Create a bar until we can create a ring with a nice thicknes/radius ratio
{
const double barAngle = randomd(0,pi);
const double sysArea = sqr(systemSpacing*0.5);
const double goalArea = sysArea * double(coreSystems);
//area = pi*r_o^2 - pi*r_i^2 = pi*(r_o^2 - r_i^2)
//sqrt(area/pi - r_i^2) = r_o
double minRadius = systemSpacing;
double maxRadius = sqrt(goalArea/pi - minRadius*minRadius);
//Add two bar systems
while((maxRadius - minRadius) > 0.2 * minRadius && coreSystems >= 5) {
addSystem(vec3d(cos(barAngle) * minRadius, randomd(-1.0,1.0) * coreHeightVariation, sin(barAngle) * minRadius), quality=250, canHaveHomeworld=false);
addSystem(vec3d(cos(barAngle) * -minRadius, randomd(-1.0,1.0) * coreHeightVariation, sin(barAngle) * -minRadius), quality=250, canHaveHomeworld=false);
coreSystems -= 2;
minRadius += systemSpacing;
maxRadius = sqrt(goalArea/pi - minRadius*minRadius);
}
uint ring = 1;
coreRingDist = minRadius;
while(coreSystems > 0) {
uint ringSystems = min(coreSystems, 7 + ring);
ringSystems = min(uint(coreRingDist * twopi / systemSpacing), coreSystems);
if(ringSystems < coreSystems && ringSystems * 2 > coreSystems)
ringSystems = (coreSystems + 1) / 2;
for(uint i = 0; i < ringSystems; ++i) {
double r = coreRingDist + randomd(-0.3, 0.0) * systemSpacing;
double ang = twopi * (double(i) + randomd(-0.25,0.25)) / double(ringSystems);
addSystem(vec3d(cos(ang) * r, randomd(-1.0, 1.0) * coreHeightVariation, sin(ang) * r), quality=100, canHaveHomeworld=false);
}
coreSystems -= ringSystems;
if(coreSystems > 0)
coreRingDist += systemSpacing;
++ring;
}
}
double armWidth = (twopi * 0.85) / double(armCount);
array<SpiralArm> arms(armCount);
{
uint playersPerArm = players / armCount;
array<uint> armPlayers(armCount, playersPerArm);
uint left = players - (playersPerArm * armCount);
while(left != 0) {
uint index = randomi(0, armCount-1);
if(armPlayers[index] == playersPerArm) {
armPlayers[index] += 1;
left -= 1;
}
}
double ang = randomd(0, pi);
for(uint i = 0; i < armCount; ++i) {
SpiralArm@ arm = arms[i];
arm.sysCount = perArm;
arm.angle = ang;
ang += twopi / double(armCount);
uint armPlayerCount = armPlayers[i];
for(uint i = 0; i < armPlayerCount; ++i)
arm.homeworlds.insertLast(uint(float(arm.sysCount) * float(i + 1) / float(armPlayerCount + 1)));
}
}
double curve = randomi(0,1) == 1 ? 1.0 : -1.0;
for(uint i = 0; i < armCount; ++i) {
SpiralArm@ arm = arms[i];
double rSq = sqr(coreRingDist + systemSpacing);
const double angFactor = max(min(coreRingDist,spiralBase*2.0), spiralBase * 0.5) * 3.0 / double(armCount);
const uint maxRing = 30;
array<vec3d> recent;
uint ringInd = 0;
for(uint j = 0, cnt = arm.sysCount; j < cnt; ++j) {
//Fill in systems, picking a variety of points and choosing a decent sensible one
vec3d pos;
while(true) {
double radius = sqrt(rSq);
double angle = arm.angle + curve * log(radius/spiralBase) / spiralCurve;
if(angle >= pi) angle -= twopi;
double sysAngSize = systemSpacing / (twopi * radius);
angle += randomd(-0.5,0.5) * (armWidth - sysAngSize) / (0.5*radius/angFactor);
double rad = radius + randomd(-0.1,0.1) * systemSpacing;
pos = vec3d(cos(angle) * rad, 0.0, sin(angle) * rad);
rSq += systemSpacing * 8000.0;
bool validPos = true;
for(uint r = 0, rcnt = recent.length; r < rcnt; ++r) {
if(pos.distanceToSQ(recent[r]) < sqr(systemSpacing)) {
validPos = false;
break;
}
}
if(validPos)
break;
}
rSq += systemSpacing * 10000.0;
if((j+1)%10 == 0) //Disrupt periodic structure that tends to form
rSq += systemSpacing * 10000.0;
if(recent.length < maxRing)
recent.insertLast(pos);
else
recent[ringInd++ % maxRing] = pos;
pos.y = randomd(-heightVariation, heightVariation);
arm.systems.insertLast(addSystem(pos));
}
for(uint j = 0, cnt = arm.homeworlds.length; j < cnt; ++j)
addPossibleHomeworld(arm.systems[arm.homeworlds[j]]);
}
}
#section all
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 429 KiB

+241
View File
@@ -0,0 +1,241 @@
#priority init 1501
import maps;
#section game
import dialogue;
#section all
#section server
import object_creation;
import influence;
import tile_resources;
import scenario;
import systems;
import map_loader;
import campaign;
#include "include/resource_constants.as"
#section all
Scenario _map;
class Scenario : Map {
Scenario() {
super();
isListed = false;
isScenario = true;
}
#section server
PersistentGfx@ wormhole;
vec3d wormholePos = vec3d(1400.0, 15.0, -750.0);
double whLife = -1.0;
double nextOpen = 180.0;
bool periodicOpen = true;
void prepareSystem(SystemData@ data, SystemDesc@ desc) {
@data.homeworlds = null;
Map::prepareSystem(data, desc);
}
bool canHaveHomeworld(SystemData@ data, Empire@ emp) {
return false;
}
void placeSystems() {
loadMap("maps/Story/scenario1.txt").generate(this);
}
void preGenerate() {
Map::preGenerate();
radius = 40000;
}
void modSettings(GameSettings& settings) {
settings.empires.length = 2;
settings.empires[0].name = locale::SCEN1_PLAYER_EMP;
settings.empires[0].shipset = "Gevron";
settings.empires[1].name = locale::SCEN1_ENEMY_EMP;
settings.empires[1].shipset = "Volkur";
settings.empires[1].type = ET_NoAI;
}
Planet@ planet(uint sys, uint ind) {
return systemData[sys].planets[ind];
}
void populate(Planet@ pl, Empire@ owner, double pop = 1.0, Object@ exportTo = null, double defense = 0.0) {
@pl.owner = owner;
pl.addPopulation(pop);
if(exportTo !is null)
pl.exportResource(owner, 0, exportTo);
if(defense > 0)
pl.spawnDefenseShips(defense);
}
void init() {
Empire@ enemy = getEmpire(1);
playerEmpire.setHostile(enemy, true);
enemy.setHostile(playerEmpire, true);
playerEmpire.Victory = -2;
wormholePos.normalize(planet(0,0).region.radius - 100.0);
populate(planet(1,1), enemy, 7.0, defense=70.0);
populate(planet(1,0), enemy, exportTo=planet(1,1), defense = 5.0);
populate(planet(2,0), enemy, 3.0, planet(1,1), defense = 44.0);
populate(planet(2,1), enemy, exportTo=planet(2,0), defense = 12.0);
populate(planet(2,3), enemy, exportTo=planet(2,0), defense = 5.0);
populate(planet(0,1), enemy, 3.0, planet(1,1), defense = 27.0);
populate(planet(0,0), enemy, exportTo=planet(0,1), defense = 7.0);
populate(planet(0,2), enemy, exportTo=planet(0,1), defense = 8.0);
populate(planet(0,3), enemy, exportTo=planet(1,1), defense = 15.0);
planet(0,1).colonize(planet(1,2));
planet(1,2).exportResource(enemy, 0, planet(1,1));
spawnFleet(enemy, planet(1,1).position + vec3d(50.0,0.0,0.0), "Defense Platform", 10);
spawnFleet(enemy, planet(1,1).position + vec3d(40.0,0.0,0.0), "Defense Platform", 10);
spawnFleet(enemy, planet(2,0).position + vec3d(40.0,0.0,0.0), "Defense Platform", 10);
spawnFleet(enemy, planet(0,1).position + vec3d(50.0,0.0,0.0), "Defense Platform", 10);
Dialogue("SCEN1_INTRO");
Dialogue("SCEN1_INTRO2")
.newObjective.checker(1, IntroCinematic(this));
Dialogue("SCEN1_CONQUER")
.checker(1, Conquer(this));
Dialogue("SCEN1_COMPLETE")
.onStart(EndCinematic(this));
}
Ship@ spawnFleet(Empire@ emp, const vec3d& pos, const string& base = "Titan", uint supBase = 25) {
auto@ leaderDsg = emp.getDesign(base);
auto@ sup3Dsg = emp.getDesign("Missile Boat");
auto@ sup1Dsg = emp.getDesign("Beamship");
auto@ sup2Dsg = emp.getDesign("Heavy Gunship");
Ship@ leader = createShip(pos, leaderDsg, emp, free=true);
for(uint i = 0; i < supBase / 2; ++i)
createShip(pos, sup1Dsg, emp, leader);
for(uint i = 0; i < supBase / 4; ++i)
createShip(pos, sup2Dsg, emp, leader);
for(uint i = 0; i < supBase / 8; ++i)
createShip(pos, sup3Dsg, emp, leader);
leader.setHoldPosition(true);
return leader;
}
void openWormhole(double timeout = -1.0) {
if(wormhole is null) {
@wormhole = PersistentGfx();
if(wormhole !is null)
wormhole.establish(wormholePos, "Wormhole", 50.0, systemData[0].planets[0].region);
}
whLife = timeout;
nextOpen = 180.0;
}
void closeWormhole() {
if(wormhole !is null) {
wormhole.stop();
@wormhole = null;
}
}
void lockWormhole() {
periodicOpen = false;
}
void tick(double time) {
if(wormhole !is null) {
if(whLife > 0) {
whLife -= time;
if(whLife <= 0)
closeWormhole();
}
}
else if(periodicOpen) {
nextOpen -= time;
if(nextOpen < 0) {
openWormhole(15.0);
if(playerEmpire.TotalMilitary * playerEmpire.TotalMilitary / 1000 < 5000.0)
spawnFleet(playerEmpire, wormholePos, "Dreadnaught", randomi(20,40))
.addMoveOrder(wormholePos + random3d(80.0,150.0));
}
}
}
#section all
};
#section server
class IntroCinematic : GuiObjectiveCheck {
uint sent = 0;
double nextSend;
PersistentGfx@ wh;
Scenario@ scen;
IntroCinematic(Scenario@ _scen) {
@scen = _scen;
}
bool start() {
scen.openWormhole();
nextSend = gameTime + 8.0;
return true;
}
bool check() {
if(sent == 2) {
if(gameTime > nextSend) {
scen.closeWormhole();
return true;
}
}
else if(gameTime > nextSend) {
nextSend = gameTime + 16.0;
if(sent == 0)
scen.spawnFleet(playerEmpire, scen.wormholePos, "Scout", 0)
.addMoveOrder(scen.wormholePos + vec3d(-50.0, 0.0, -100.0));
else
scen.spawnFleet(playerEmpire, scen.wormholePos, "Dreadnaught", 35)
.addMoveOrder(scen.wormholePos + vec3d(100.0, 0.0, 50.0));
++sent;
}
return false;
}
};
class Conquer : GuiObjectiveCheck {
Scenario@ scen;
Conquer(Scenario@ _scen) {
@scen = _scen;
}
bool check() {
if(getEmpire(1).fleetCount > 0)
return false;
auto@ systemData = scen.systemData;
for(uint i = 0, cnt = systemData.length; i < cnt; ++i) {
auto@ sys = systemData[i];
for(uint j = 0, jcnt = sys.planets.length; j < jcnt; ++j) {
auto@ pl = sys.planets[j];
if(pl.owner.valid && pl.owner !is playerEmpire)
return false;
}
}
return true;
}
};
class EndCinematic : DialogueAction {
Scenario@ scen;
EndCinematic(Scenario@ _scen) { @scen = _scen; }
bool start() {
scen.openWormhole();
completeCampaignScenario("InevitableConquest");
return true;
}
};
#section all
+26
View File
@@ -0,0 +1,26 @@
//Starting System
System: Varkus
Position: (0, 0, 0)
Effect: MakeStar(Temperature = 5778, Radius = 75)
Effect: MakePlanet(Water)
Effect: MakePlanet(Titanium)
Effect: MakePlanet(Meat)
Effect: MakePlanet(Grain)
Effect: MakeAsteroid(Iron)
Effect: MakeAsteroid(Aluminum)
System: Pidion
Position: (3900, -450, 2400)
Effect: MakeStar(Temperature = 8500, Radius = 80)
Effect: MakePlanet(Water)
Effect: MakePlanet(Grain)
Effect: MakePlanet(Iron)
Effect: MakeAsteroid(Water)
System: Nolvir
Position: (-1850, 100, 3600)
Effect: MakeStar(Temperature = 3200, Radius = 110)
Effect: MakePlanet(Textiles)
Effect: MakePlanet(Fruit)
Effect: MakePlanet(Fulrate)
Effect: MakePlanet(Water)
File diff suppressed because it is too large Load Diff
+65
View File
@@ -0,0 +1,65 @@
//Enemy gate system
System: Odatak
MakeStar(Temperature = 5778, Radius = 75)
MakePlanet(Water, Conditions = False)
MakePlanet(Meat, Conditions = False)
MakePlanet(Salts, Conditions = False)
MakePlanet(Water, Conditions = False)
MakeAsteroid()
MakeAsteroid()
MakeAsteroid()
//Spacewood's system
System: Lihls
Position: (5000, 0, 0)
MakeStar(Temperature = 1000, Radius = 75)
MakePlanet(Meat, Grid Size = (17, 10), Conditions = False, Moons = False)
AddPlanetResource(Water)
AddResource(Labor, +20)
AddPopulation(3.0)
Rename(Spacewood)
NoNeedPopulationForLevel()
MakePlanet(NativeGold, Conditions = False)
MakePlanet(Fruit, Conditions = False)
MakePlanet(Grain, Conditions = False)
MakeAsteroid()
//Phasite system
System: Xaste
Position: (8000, 120, 8000)
MakeStar(Temperature = 2500, Radius = 75)
MakePlanet(Meat, Conditions = False)
MakePlanet(Fish, Conditions = False)
MakePlanet(Water, Conditions = False)
MakePlanet(Phasite, Conditions = False)
MakeAsteroid()
MakeAsteroid()
MakeArtifact(PowerCell)
//Enemy colonized system
System: Yingmow
Position: (9000, -60, 15000)
MakeStar(Temperature = 8000, Radius = 75)
MakePlanet(Neutronium, Conditions = False)
MakePlanet(Fish, Conditions = False)
MakePlanet(Water, Conditions = False)
MakePlanet(Titanium, Conditions = False)
MakeAsteroid()
MakeAsteroid()
MakeAsteroid()
MakeAsteroid()
//Neutral system
System: Darolco
Position: (2000, -60, 9400)
NameSystem(Darolco)
MakeStar(Temperature = 4000, Radius = 75)
MakePlanet(Pekelm, Conditions = False)
MakePlanet(Meat, Conditions = False)
MakePlanet(Water, Conditions = False)
MakePlanet(Water, Conditions = False)
MakeAsteroid()