Files
starruler-linux/scripts/server/artifact_seeding.as
T
2018-07-17 14:15:37 +02:00

296 lines
7.5 KiB
ActionScript

import saving;
import object_creation;
import statuses;
from statuses import StatusHook;
from map_generation import generatedGalaxies, GalaxyData;
from empire import Creeps;
import systems;
import system_pathing;
import artifacts;
import Artifact@ createArtifact(const vec3d&, const ArtifactType@, Region@ region = null) from "objects.Artifact";
import bool getCheatsEverOn() from "cheats";
locked_int ArtifactCount = 0;
double storedEnergy = 0.0;
const double SPAWN_OFFSET = 1000.0;
const double MOVE_OFFSET = 500.0;
const double MOVE_VARIANCE = 200.0;
const double ARTIF_OFFSET = 350.0;
const double ARTIF_VARIANCE = 50.0;
void tick(double time) {
double factor = double(systemCount) * config::TARGET_ARTIFACTS_PER_SYSTEM;
double count = ArtifactCount.value;
if(count != 0)
factor /= count;
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
Empire@ other = getEmpire(i);
storedEnergy += other.EnergyIncome * time * factor * other.EnergyEfficiency;
}
if(storedEnergy >= config::ENERGY_PER_SEEDSHIP) {
storedEnergy = 0.0;
Ship@ ship = createShip(vec3d(1e10, 1e10, 1e10),
Creeps.getDesign("Seed Ship"), Creeps, free = true);
ship.addStatus(getStatusID("SeedShip"));
}
}
void save(SaveFile& file) {
file << ArtifactCount;
file << storedEnergy;
}
void load(SaveFile& file) {
if(file >= SV_0026) {
file >> ArtifactCount;
file >> storedEnergy;
}
}
//SeedShip()
// This behaves as a seed ship.
class SeedData {
array<uint> targets;
};
class SeedShip : StatusHook {
void onCreate(Object& obj, Status@ status, any@ data) override {
SeedData seed;
data.store(@seed);
//Find target empire
Empire@ targEmp;
double totalGen = 0.0;
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
Empire@ other = getEmpire(i);
if(!other.major)
continue;
totalGen += other.EnergyIncome;
}
double roll = randomd(0.0, totalGen);
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
Empire@ other = getEmpire(i);
if(!other.major)
continue;
@targEmp = other;
double gen = targEmp.EnergyIncome;
if(roll <= gen)
break;
roll -= gen;
}
//Find target system
DataList@ objs = targEmp.getPlanets();
array<Planet@> planets;
Object@ rec;
while(receive(objs, rec)) {
Planet@ pl = cast<Planet>(rec);
if(pl is null)
continue;
planets.insertLast(pl);
}
if(planets.length == 0) {
obj.destroy();
return;
}
Planet@ targPl = planets[randomi(0, planets.length - 1)];
SystemDesc@ targSys = getSystem(targPl.region);
if(targSys is null) {
obj.destroy();
return;
}
//Find the target galaxy
const GalaxyData@ targGlx;
for(uint i = 0, cnt = generatedGalaxies.length; i < cnt; ++i) {
auto@ glx = generatedGalaxies[i];
if(targSys.position.distanceTo(glx.origin) < glx.radius) {
@targGlx = glx;
break;
}
}
if(targGlx is null) {
obj.destroy();
return;
}
//Create line for path
vec3d offset = (targSys.position - targGlx.origin).normalized(targGlx.radius);
vec3d startPos = targGlx.origin + offset;
vec3d endPos = targGlx.origin - offset;
//Find path start and end
SystemDesc@ pathStart;
double startDist = INFINITY;
SystemDesc@ pathEnd;
double endDist = INFINITY;
for(uint i = 0, cnt = targGlx.systems.length; i < cnt; ++i) {
auto@ other = targGlx.systems[i];
double d = other.position.distanceToSQ(startPos);
if(d < startDist) {
startDist = d;
@pathStart = other;
}
d = other.position.distanceToSQ(endPos);
if(d < endDist) {
endDist = d;
@pathEnd = other;
}
}
//Initial position
vec3d prevPos = pathStart.position;
prevPos += (startPos - prevPos).normalized(pathStart.radius + SPAWN_OFFSET);
obj.teleportTo(prevPos);
//Path towards target
SystemPath path;
path.generate(pathStart, targSys);
array<SystemDesc@> visited;
if(path.valid) {
for(uint i = 0, cnt = path.pathSize; i < cnt; ++i) {
auto@ other = path.pathNode[i];
vec3d newPos = other.position;
newPos += (prevPos - newPos).normalized(other.radius - MOVE_OFFSET) + random3d(0.0, MOVE_VARIANCE);
obj.addMoveOrder(newPos, append=true);
prevPos = newPos;
if(other !is targSys)
visited.insertLast(other);
}
}
else {
vec3d newPos = targSys.position;
newPos += (prevPos - newPos).normalized(targSys.radius - MOVE_OFFSET) + random3d(0.0, MOVE_VARIANCE);
obj.addMoveOrder(newPos, append=true);
prevPos = newPos;
}
path.generate(targSys, pathEnd);
if(path.valid) {
for(uint i = 1, cnt = path.pathSize; i < cnt; ++i) {
auto@ other = path.pathNode[i];
vec3d newPos = other.position;
newPos += (prevPos - newPos).normalized(other.radius - MOVE_OFFSET) + random3d(0.0, MOVE_VARIANCE);
obj.addMoveOrder(newPos, append=true);
prevPos = newPos;
if(other !is targSys)
visited.insertLast(other);
}
}
vec3d newPos = pathEnd.position;
newPos += (endPos - prevPos).normalized(pathEnd.radius + SPAWN_OFFSET);
obj.addMoveOrder(newPos, append=true);
seed.targets.insertLast(targSys.index);
if(visited.length > 0) {
for(uint i = 1, cnt = config::ARTIFACTS_PER_SEEDSHIP; i < cnt; ++i)
seed.targets.insertLast(visited[randomi(0, visited.length-1)].index);
}
}
bool onTick(Object& obj, Status@ status, any@ data, double time) override {
if(obj.orderCount == 0) {
playParticleSystem("SeedShipBoom", obj.position, obj.rotation, obj.radius, obj.visibleMask);
obj.destroy();
return false;
}
Region@ reg = obj.region;
if(reg is null)
return true;
SystemDesc@ sys = getSystem(reg);
if(sys is null)
return true;
SeedData@ seed;
data.retrieve(@seed);
for(uint i = 0, cnt = seed.targets.length; i < cnt; ++i) {
if(seed.targets[i] == sys.index) {
if(sys.position.distanceTo(obj.position) < sys.radius - ARTIF_OFFSET) {
const ArtifactType@ type = getSeedArtifactType();
auto@ artifact = createArtifact(obj.position + random3d(obj.radius + 1.0, ARTIF_VARIANCE), type);
artifact.orbitAround(reg.position);
seed.targets.removeAt(i);
}
break;
}
}
return true;
}
void onObjectDestroy(Object& obj, Status@ status, any@ data) override {
for(uint i = 0, cnt = config::ARTIFACTS_SEEDSHIP_DEATH; i < cnt; ++i) {
const ArtifactType@ type = getSeedArtifactType();
vec3d pos = obj.position + random3d(type.physicalSize * 1.5, type.physicalSize * 3.0);
auto@ artifact = createArtifact(pos, type);
if(obj.region !is null)
artifact.orbitAround(obj.region.position);
}
if(obj.type == OT_Ship) {
Empire@ killer = cast<Ship>(obj).getKillCredit();
if(killer !is null && killer.valid && !getCheatsEverOn()) {
if(killer is playerEmpire)
unlockAchievement("ACH_SPILLED_SEED");
else if(mpServer && killer.player !is null)
clientAchievement(killer.player, "ACH_SPILLED_SEED");
}
}
}
void save(Status@ status, any@ data, SaveFile& file) override {
SeedData@ seed;
data.retrieve(@seed);
uint cnt = seed.targets.length;
file << cnt;
for(uint i = 0; i < cnt; ++i) {
uint id = seed.targets[i];
file << id;
}
}
void load(Status@ status, any@ data, SaveFile& file) override {
SeedData seed;
data.store(@seed);
uint cnt = 0;
file >> cnt;
seed.targets.length = cnt;
for(uint i = 0; i < cnt; ++i) {
uint id = 0;
file >> id;
seed.targets[i] = id;
}
}
};
class GravitarShip : StatusHook {
bool onTick(Object& obj, Status@ status, any@ data, double time) override {
if(obj.orderCount == 0 && randomi(0,10) == 0) {
playParticleSystem("SeedShipBoom", obj.position, obj.rotation, obj.radius, obj.visibleMask);
obj.destroy();
return false;
}
return true;
}
};