diff --git a/data/components/region_objects.txt b/data/components/region_objects.txt index 9fc56f1..b7165e7 100644 --- a/data/components/region_objects.txt +++ b/data/components/region_objects.txt @@ -1,17 +1,17 @@ Object.RegionObjects : regions.RegionObjects::RegionObjects { local: safe uint get_planetCount() const; - Planet@ get_planets(uint index) const; + safe Planet@ get_planets(uint index) const; safe uint getPlanetCount(Empire@ emp) const; safe uint get_anomalyCount() const; - Anomaly@ get_anomalies(uint index) const; + safe Anomaly@ get_anomalies(uint index) const; safe uint get_asteroidCount() const; - Asteroid@ get_asteroids(uint index) const; + safe Asteroid@ get_asteroids(uint index) const; safe uint get_objectCount() const; Object@ get_objects(uint index) const; Object@ getOrbitObject(vec3d point) const; safe uint get_starCount() const; - Star@ get_stars(uint index) const; + safe Star@ get_stars(uint index) const; safe double get_starTemperature() const; safe double get_starRadius() const; @@ -48,11 +48,11 @@ server: async relocking void requestConstructionOn(Object& onObj, uint constrId); async void renameSystem(string name); - Object@[] getPickups(); - Object@[] getPlanets(); - Object@[] getAnomalies(); - Object@[] getArtifacts(); - Object@[] getAsteroids(); + safe Object@[] getPickups(); + safe Object@[] getPlanets(); + safe Object@[] getAnomalies(); + safe Object@[] getArtifacts(); + safe Object@[] getAsteroids(); void addStrategicIcon(int level, Object& obj, Node& node); void removeStrategicIcon(int level, Node& node); diff --git a/data/events/misc.txt b/data/events/misc.txt index ecd7aeb..9ae7cc9 100644 --- a/data/events/misc.txt +++ b/data/events/misc.txt @@ -5,4 +5,6 @@ void sendPingAllied(vec3d position, uint type = 0) -> server::pings::sendPingAll void showPing(Empire@ fromEmpire, vec3d position, uint type = 0) -> client::pings::showPing int getUnlockTag_client(string ident) -> local server::unlock_tags::getUnlockTag_client string getUnlockTagIdent_client(int ident) -> local server::unlock_tags::getUnlockTagIdent +int getObjectStat_client(string ident) -> local server::object_stats::getObjectStatId_client +string getObjectStatIdent_client(int ident) -> local server::object_stats::getObjectStatIdent bool hasInvasionMap() -> local server::Invasion.InvasionMap::hasInvasionMap diff --git a/scripts/definitions/bonus_effects.as b/scripts/definitions/bonus_effects.as index d167e81..cf4f11f 100644 --- a/scripts/definitions/bonus_effects.as +++ b/scripts/definitions/bonus_effects.as @@ -27,6 +27,7 @@ import generic_hooks; import void gainRandomCard(Empire@ emp) from "card_effects"; #section server +from object_stats import ObjectStatType, getObjectStat; from objects.Asteroid import createAsteroid; from objects.Anomaly import createAnomaly; from empire import Creeps; @@ -3314,3 +3315,38 @@ class SetSystemAssignGroup : BonusEffect { } #section all }; + +class ModStat : BonusEffect { + Document doc("Permanently modify a stat of the object this is called on."); + Argument stat(AT_ObjectStat, doc="Stat to modify. Type anything and a new stat with that name will be created. Adding # in the name indicates the stat is integral, adding & in the name indicates the stat is server-only."); + Argument mode(AT_ObjectStatMode, doc="The way to modify the stat."); + Argument value(AT_Decimal, doc="The value to modify the stat by."); + Argument for_empire(AT_Boolean, "False", doc="If set, the stat is modified only inside the triggering empire's context, instead of for the object globally."); + Argument on_system(AT_Boolean, "False", doc="If set, instead modify the stat on the system the triggering object is in instead."); + +#section server + const ObjectStatType@ objStat; + + bool instantiate() override { + if(!BonusEffect::instantiate()) + return false; + @objStat = getObjectStat(stat.str); + return true; + } + + void activate(Object@ obj, Empire@ emp) const override { + if(obj is null || objStat is null) + return; + if(on_system.boolean) { + @obj = obj.region; + if(obj is null) + return; + } + + if(!for_empire.boolean) + @emp = null; + + objStat.mod(obj, emp, mode.integer, mode.decimal); + } +#section all +}; diff --git a/scripts/definitions/generic_effects.as b/scripts/definitions/generic_effects.as index be29a9b..eb17885 100644 --- a/scripts/definitions/generic_effects.as +++ b/scripts/definitions/generic_effects.as @@ -19,6 +19,7 @@ import planet_types; #section server import object_creation; from components.ObjectManager import getDefenseDesign; +from object_stats import ObjectStatType, getObjectStat; #section all //ModSupportBuildSpeed() @@ -5541,3 +5542,193 @@ class ModConstructionHPBonusAttribute : GenericEffect { } #section all }; + +class ModObjectStat : GenericEffect { + Document doc("Modify a stat of the object this is called on while the effect is active."); + Argument stat(AT_ObjectStat, doc="Stat to modify. Type anything and a new stat with that name will be created. Adding # in the name indicates the stat is integral, adding & in the name indicates the stat is server-only."); + Argument mode(AT_ObjectStatMode, doc="The way to modify the stat."); + Argument value(AT_Decimal, doc="The value to modify the stat by."); + Argument for_empire(AT_Boolean, "False", doc="If set, the stat is modified only inside the triggering empire's context, instead of for the object globally."); + +#section server + const ObjectStatType@ objStat; + + bool instantiate() override { + if(!GenericEffect::instantiate()) + return false; + @objStat = getObjectStat(stat.str); + return true; + } + + void enable(Object& obj, any@ data) const override { + if(objStat is null) + return; + + Empire@ emp = obj.owner; + if(!for_empire.boolean) + @emp = null; + + objStat.mod(obj, emp, mode.integer, value.decimal); + } + + void ownerChange(Object& obj, any@ data, Empire@ prevOwner, Empire@ newOwner) const override { + if(objStat is null) + return; + + if(for_empire.boolean) { + objStat.reverse(obj, prevOwner, mode.integer, value.decimal); + objStat.mod(obj, newOwner, mode.integer, value.decimal); + } + } + + void disable(Object& obj, any@ data) const override { + if(objStat is null) + return; + + Empire@ emp = obj.owner; + if(!for_empire.boolean) + @emp = null; + + objStat.reverse(obj, emp, mode.integer, value.decimal); + } +#section all +}; + +class ModRegionStat : GenericEffect { + Document doc("Modify a stat of the region this is in."); + Argument stat(AT_ObjectStat, doc="Stat to modify. Type anything and a new stat with that name will be created. Adding # in the name indicates the stat is integral, adding & in the name indicates the stat is server-only."); + Argument mode(AT_ObjectStatMode, doc="The way to modify the stat."); + Argument value(AT_Decimal, doc="The value to modify the stat by."); + Argument for_empire(AT_Boolean, "False", doc="If set, the stat is modified only inside the triggering empire's context, instead of for the object globally."); + +#section server + const ObjectStatType@ objStat; + + bool instantiate() override { + if(!GenericEffect::instantiate()) + return false; + @objStat = getObjectStat(stat.str); + return true; + } + + void enable(Object& obj, any@ data) const override { + if(objStat is null) + return; + + Region@ reg = obj.region; + if(reg is null) + return; + + Empire@ emp = obj.owner; + if(!for_empire.boolean) + @emp = null; + + objStat.mod(reg, emp, mode.integer, value.decimal); + } + + void ownerChange(Object& obj, any@ data, Empire@ prevOwner, Empire@ newOwner) const override { + if(objStat is null) + return; + + if(for_empire.boolean) { + Region@ reg = obj.region; + if(reg is null) + return; + + objStat.reverse(reg, prevOwner, mode.integer, value.decimal); + objStat.mod(reg, newOwner, mode.integer, value.decimal); + } + } + + void regionChange(Object& obj, any@ data, Region@ fromRegion, Region@ toRegion) const { + if(objStat is null) + return; + + Empire@ emp = obj.owner; + if(!for_empire.boolean) + @emp = null; + + if(fromRegion !is null) + objStat.reverse(fromRegion, emp, mode.integer, value.decimal); + if(toRegion !is null) + objStat.mod(toRegion, emp, mode.integer, value.decimal); + } + + void disable(Object& obj, any@ data) const override { + if(objStat is null) + return; + + Region@ reg = obj.region; + if(reg is null) + return; + + Empire@ emp = obj.owner; + if(!for_empire.boolean) + @emp = null; + + objStat.reverse(reg, emp, mode.integer, value.decimal); + } +#section all +}; + +class GenerateObjectStat : GenericEffect { + Document doc("Generate an amount of an object stat per second while this effect is active."); + Argument stat(AT_ObjectStat, doc="Stat to modify. Type anything and a new stat with that name will be created. Adding & in the name indicates the stat is server-only."); + Argument per_second(AT_Decimal, doc="The value to add to the stat per second."); + Argument for_empire(AT_Boolean, "False", doc="If set, the stat is modified only inside the triggering empire's context, instead of for the object globally."); + +#section server + const ObjectStatType@ objStat; + + bool instantiate() override { + if(!GenericEffect::instantiate()) + return false; + @objStat = getObjectStat(stat.str); + return true; + } + + void tick(Object& obj, any@ data, double time) const override { + if(objStat is null) + return; + + Empire@ emp = obj.owner; + if(!for_empire.boolean) + @emp = null; + + objStat.mod(obj, emp, OSM_Add, per_second.decimal * time); + } +#section all +}; + +class GenerateRegionStat : GenericEffect { + Document doc("Generate an amount of a stat per second on the region this object is in while this effect is active."); + Argument stat(AT_ObjectStat, doc="Stat to modify. Type anything and a new stat with that name will be created. Adding & in the name indicates the stat is server-only."); + Argument per_second(AT_Decimal, doc="The value to add to the stat per second."); + Argument for_empire(AT_Boolean, "False", doc="If set, the stat is modified only inside the triggering empire's context, instead of for the object globally."); + +#section server + const ObjectStatType@ objStat; + + bool instantiate() override { + if(!GenericEffect::instantiate()) + return false; + @objStat = getObjectStat(stat.str); + return true; + } + + void tick(Object& obj, any@ data, double time) const override { + if(objStat is null) + return; + + Region@ reg = obj.region; + if(reg is null) + return; + + Empire@ emp = obj.owner; + if(!for_empire.boolean) + @emp = null; + + objStat.mod(reg, emp, OSM_Add, per_second.decimal * time); + } +#section all +}; diff --git a/scripts/definitions/hooks.as b/scripts/definitions/hooks.as index 7146d1a..06db8ed 100644 --- a/scripts/definitions/hooks.as +++ b/scripts/definitions/hooks.as @@ -28,6 +28,10 @@ import int getTechnologyID(const string&) from "research"; import string getTechnologyIdent(int id) from "research"; import int getUnlockTag(const string& ident, bool create = true) from "unlock_tags"; import string getUnlockTagIdent(int id) from "unlock_tags"; +import int getObjectStatId(const string& ident, bool create = true) from "object_stats"; +import string getObjectStatIdent(int id) from "object_stats"; +import string getObjectStatMode(int id) from "object_stats"; +import int getObjectStatMode(const string& ident) from "object_stats"; import int getSystemFlag(const string& ident, bool create = true) from "system_flags"; import string getSystemFlagIdent(int id) from "system_flags"; import int getInfluenceCardID(const string& ident) from "influence"; @@ -95,6 +99,8 @@ enum ArgumentType { AT_ValueDef, AT_File, AT_UnlockTag, + AT_ObjectStat, + AT_ObjectStatMode, AT_SystemFlag, AT_Custom, AT_VarArgs, @@ -535,6 +541,9 @@ final class Argument { case AT_UnlockTag: integer = getUnlockTag(value); return true; + case AT_ObjectStat: + integer = getObjectStatId(value); + return true; case AT_SystemFlag: integer = getSystemFlag(value); return true; @@ -559,6 +568,9 @@ final class Argument { return false; } return true; + case AT_ObjectStatMode: + integer = int(getObjectStatMode(value)); + return true; case AT_PlanetResource: if(value.equals_nocase("null")) { integer = -1; @@ -668,6 +680,8 @@ final class Argument { return getGlobal(integer).ident; case AT_UnlockTag: return getUnlockTagIdent(integer); + case AT_ObjectStat: + return getObjectStatIdent(integer); case AT_SystemFlag: return getSystemFlagIdent(integer); case AT_Boolean: @@ -762,6 +776,8 @@ final class Argument { return getEmpAttributeIdent(integer); case AT_AttributeMode: return getAttributeModeIdent(integer); + case AT_ObjectStatMode: + return getObjectStatMode(integer); case AT_EmpireResource: if(integer >= 0 && uint(integer) < empResources.length) return empResources[integer]; diff --git a/scripts/definitions/object_stats.as b/scripts/definitions/object_stats.as new file mode 100644 index 0000000..96af9cb --- /dev/null +++ b/scripts/definitions/object_stats.as @@ -0,0 +1,154 @@ +#priority init 10000 +import saving; + +/*enum PresetStats { +};*/ + +const array preset_stats = {}; + +string getObjectStatMode(int id) { + switch(id) + { + case OSM_Set: return "Set"; + case OSM_Add: return "Add"; + case OSM_Multiply: return "Multiply"; + } + return "Set"; +} + +int getObjectStatMode(const string& ident) { + if(ident.equals_nocase("set")) + return OSM_Set; + if(ident.equals_nocase("add")) + return OSM_Add; + if(ident.equals_nocase("multiply")) + return OSM_Multiply; + return OSM_Set; +} + +#section client +int getObjectStatId(const string& ident, bool create = true) { + return getObjectStat_client(ident); +} + +string getObjectStatIdent(int id) { + return getObjectStatIdent_client(id); +} + +#section server-side +const double OBJECT_STAT_SYNC_RESOLUTION = 0.01; + +tidy class ObjectStatType { + int id; + string ident; + bool isInt = false; + bool shouldSync = true; + + ObjectStatType(const string& name) + { + ident = name; + isInt = name.contains("#"); + shouldSync = !name.contains("&"); + } + + uint64 key(Empire@ forEmpire) const { + return OBJ_STAT_MASK | uint64(forEmpire.id) << 32 | uint64(id); + } + + void mod(Object@ obj, Empire@ emp, int mode, double value) const { + if(isInt) { + int dirtyResolution = 0; + if(!shouldSync) + dirtyResolution = -1; + obj.modStatInt(key(emp), ObjectStatMode(mode), int(value), dirtyResolution); + } + else { + double dirtyResolution = OBJECT_STAT_SYNC_RESOLUTION; + if(!shouldSync) + dirtyResolution = -1.0; + obj.modStatDouble(key(emp), ObjectStatMode(mode), int64(value), dirtyResolution); + } + } + + void reverse(Object@ obj, Empire@ emp, int mode, double value) const { + switch(mode) { + case OSM_Set: + throw("Cannot reverse a stat modified with Set mode."); + return; + case OSM_Multiply: + if(value == 0.0) { + throw("Cannot reverse a stat multiplied by 0."); + return; + } + value = 1.0 / value; + break; + case OSM_Add: + value *= -1.0; + break; + } + + mod(obj, emp, mode, value); + } +}; + +array objectStats; +dictionary objectStatIdents; + +void preInit() { + for(uint i = 0, cnt = preset_stats.length; i < cnt; ++i) + getObjectStat(preset_stats[i], create=true); +} + +uint getObjectStatCount() { + return objectStats.length; +} + +const ObjectStatType@ getObjectStat(int id) { + if(id < 0 || uint(id) >= objectStats.length) + return null; + return objectStats[id]; +} + +const ObjectStatType@ getObjectStat(const string& ident, bool create = true) { + int id = -1; + if(!objectStatIdents.get(ident, id)) { + if(create) { + id = int(objectStats.length); + ObjectStatType stat(ident); + stat.id = id; + objectStats.insertLast(stat); + objectStatIdents.set(ident, id); + return stat; + } + else { + return null; + } + } + return objectStats[id]; +} + +int getObjectStatId(const string& ident, bool create = true) { + auto@ stat = getObjectStat(ident, create); + if(stat is null) + return -1; + else + return stat.id; +} + +int getObjectStatId_client(string ident) { + int id = -1; + if(objectStatIdents.get(ident, id)) + return id; + return -1; +} + +string getObjectStatIdent(int id) { + if(id < 0 || uint(id) >= objectStats.length) + return ""; + return objectStats[id].ident; +} + +void saveIdentifiers(SaveFile& file) { + for(uint i = 0, cnt = objectStats.length; i < cnt; ++i) + file.addIdentifier(SI_ObjectStat, int(i), objectStats[i].ident); +} diff --git a/scripts/definitions/saving.as b/scripts/definitions/saving.as index 5c49014..99f0719 100644 --- a/scripts/definitions/saving.as +++ b/scripts/definitions/saving.as @@ -30,6 +30,7 @@ enum SaveIdentifier { SI_RandomEventOption, SI_PlanetLevelChain, SI_AttitudeType, + SI_ObjectStat, }; enum SaveVersion { @@ -200,6 +201,7 @@ enum SaveVersion { SV_0160, SV_0161, SV_0162, + SV_0163, SV_NEXT, SV_CURRENT = SV_NEXT - 1, @@ -231,10 +233,56 @@ void saveIdentifiers(SaveFile& file) { file.startVersion = START_VERSION; } +const uint64 OBJ_STAT_MASK = 0x03 << 56; void saveObjectStates(Object& obj, SaveFile& file) { file << obj.region; + + uint statCount = obj.getStatCount(); + file << statCount; + for(uint i = 0; i < statCount; ++i) { + uint64 statId = obj.getStatIdByIndex(i); + int64 statValue = obj.getStatValueByIndex(i); + + int leftKey = int((statId & 0xFFFFFFFF00000000) >> 32); + int rightKey = int(statId & 0x00000000FFFFFFFF); + file << leftKey; + file << statValue; + + if(statId & OBJ_STAT_MASK != 0) + file.writeIdentifier(SI_ObjectStat, rightKey); + else + file << rightKey; + } } void loadObjectStates(Object& obj, SaveFile& file) { file >> obj.region; + if(file >= SV_0163) + { + uint statCount = 0; + file >> statCount; + + for(uint i = 0; i < statCount; ++i) { + uint64 key = 0; + + int leftKey = 0; + file >> leftKey; + key |= uint64(leftKey)<<32; + + int64 value = 0; + file >> value; + + if(key & OBJ_STAT_MASK != 0) { + int id = file.readIdentifier(SI_ObjectStat); + key |= id; + } + else { + int id = 0; + file >> id; + key |= id; + } + + obj.modStatInt(key, OSM_Set, value); + } + } } diff --git a/scripts/definitions/version.as b/scripts/definitions/version.as index 0418402..530a03e 100644 --- a/scripts/definitions/version.as +++ b/scripts/definitions/version.as @@ -1,9 +1,9 @@ #section menu void preInit() { - MP_VERSION = 79; + MP_VERSION = 80; } #section all const bool STEAM_EQUIV_BUILD = IS_STEAM_BUILD; const string GAME_VERSION = "v2.0.2"; -const string SCRIPT_VERSION = "r5094"; +const string SCRIPT_VERSION = "r5095"; diff --git a/scripts/gui/editor/fields.as b/scripts/gui/editor/fields.as index ae6a748..a011aa9 100644 --- a/scripts/gui/editor/fields.as +++ b/scripts/gui/editor/fields.as @@ -1000,6 +1000,14 @@ Field@ makeField(ArgumentType type, IGuiElement@ parent, const recti& pos) { fld.addOption("Multiply", "Multiply (Add a multiplication: the entire value including Add is multiplied)"); return fld; } + case AT_ObjectStatMode: + { + SelectionField fld(parent, pos); + fld.addOption("Add", "Add (Add a value to the object stat)"); + fld.addOption("Multiply", "Multiply (Multiply the object stat by a value"); + fld.addOption("Set", "Set (Set object stat to a new value)"); + return fld; + } case AT_EmpireResource: { SelectionField fld(parent, pos); diff --git a/scripts/server/empire_ai/weasel/searches.as b/scripts/server/empire_ai/weasel/searches.as index 1c9a258..2ab96a0 100644 --- a/scripts/server/empire_ai/weasel/searches.as +++ b/scripts/server/empire_ai/weasel/searches.as @@ -55,6 +55,7 @@ Object@ findEnemy(Region@ region, Empire@ emp, uint empireMask, bool fleets = tr array@ findEnemies(Region@ region, Empire@ emp, uint empireMask, bool fleets = true, bool stations = true, bool planets = false) { array@ objs = findInBox(region.position - vec3d(region.radius), region.position + vec3d(region.radius), empireMask); + array outObjs; for(int i = objs.length-1; i >= 0; --i) { Object@ obj = objs[i]; Empire@ owner = obj.owner; @@ -102,14 +103,51 @@ array@ findEnemies(Region@ region, Empire@ emp, uint empireMask, bool f } } - if(remove) - objs.removeAt(i); + if(!remove) + outObjs.insertLast(obj); } - return objs; + return outObjs; } array@ findType(Region@ region, Empire@ emp, uint objectType, uint empireMask = ~0) { - array@ objs = findInBox(region.position - vec3d(region.radius), region.position + vec3d(region.radius), empireMask); + // Specialized for safe object buckets + array@ objs; + DataList@ data; + switch(objectType) + { + case OT_Planet: + @data = region.getPlanets(); + break; + case OT_Pickup: + @data = region.getPickups(); + break; + case OT_Anomaly: + @data = region.getAnomalies(); + break; + case OT_Artifact: + @data = region.getArtifacts(); + break; + case OT_Asteroid: + @data = region.getAsteroids(); + break; + } + + if(data !is null) + { + @objs = array(); + Object@ obj; + while(receive(data, obj)) { + if(obj !is null) + objs.insertLast(obj); + } + } + else { + // No object bucket retrieval mechanism, do a full physics search + @objs = findInBox(region.position - vec3d(region.radius), region.position + vec3d(region.radius), empireMask); + } + + // Generic search using physics system + array outObjs; for(int i = objs.length-1; i >= 0; --i) { Object@ obj = objs[i]; Empire@ owner = obj.owner; @@ -133,10 +171,10 @@ array@ findType(Region@ region, Empire@ emp, uint objectType, uint empi remove = true; } - if(remove) - objs.removeAt(i); + if(!remove) + outObjs.insertLast(obj); } - return objs; + return outObjs; } array@ findAll(Region@ region, uint empireMask = ~0) { diff --git a/scripts/server/objects/Artifact.as b/scripts/server/objects/Artifact.as index 1eb8aef..457b78d 100644 --- a/scripts/server/objects/Artifact.as +++ b/scripts/server/objects/Artifact.as @@ -215,7 +215,6 @@ tidy class ArtifactScript { void load(Artifact& obj, SaveFile& file) { loadObjectStates(obj, file); @type = getArtifactType(file.readIdentifier(SI_Artifact)); - makeMesh(obj); obj.ArtifactType = type.id; file >> cast(obj.Abilities); file >> cast(obj.Orbit); @@ -225,6 +224,10 @@ tidy class ArtifactScript { file >> expire; } + void postLoad(Artifact& obj) { + makeMesh(obj); + } + void save(Artifact& obj, SaveFile& file) { saveObjectStates(obj, file); file.writeIdentifier(SI_Artifact, type.id); diff --git a/scripts/server/objects/Asteroid.as b/scripts/server/objects/Asteroid.as index 4a46c1a..aea957a 100644 --- a/scripts/server/objects/Asteroid.as +++ b/scripts/server/objects/Asteroid.as @@ -78,6 +78,9 @@ tidy class AsteroidScript { } obj.HasBase = (obj.owner !is null && obj.owner.valid) ? 1.f : 0.f; + } + + void postLoad(Asteroid& obj) { makeMesh(obj); } diff --git a/scripts/server/regions/RegionObjects.as b/scripts/server/regions/RegionObjects.as index 4a6881a..110ddc5 100644 --- a/scripts/server/regions/RegionObjects.as +++ b/scripts/server/regions/RegionObjects.as @@ -34,6 +34,8 @@ tidy class RegionObjects : Component_RegionObjects, Savable { Orbital@[] orbitalList; Asteroid@[] asteroidList; Anomaly@[] anomalyList; + Pickup@[] pickupList; + Artifact@[] artifactList; Object@[] resourceHolders; RegionEffect@[] effects; int nextEffectId = 1; @@ -44,6 +46,13 @@ tidy class RegionObjects : Component_RegionObjects, Savable { float combatTimer = 60.0; double StarTemperature = 0; double StarRadius = 0; + + PlanetBucket planetBucket; + PickupBucket pickupBucket; + AsteroidBucket asteroidBucket; + ArtifactBucket artifactBucket; + AnomalyBucket anomalyBucket; + StarBucket starBucket; double PeriodicUpdate = 0.0; double PeriodicTime = 0.0; @@ -88,8 +97,11 @@ tidy class RegionObjects : Component_RegionObjects, Savable { uint cnt = 0; msg >> cnt; starList.length = cnt; - for(uint i = 0; i < cnt; ++i) + for(uint i = 0; i < cnt; ++i) { msg >> starList[i]; + if(starList[i] !is null) + starBucket.add(starList[i]); + } msg >> cnt; objectList.length = cnt; @@ -98,8 +110,11 @@ tidy class RegionObjects : Component_RegionObjects, Savable { msg >> cnt; planetList.length = cnt; - for(uint i = 0; i < cnt; ++i) + for(uint i = 0; i < cnt; ++i) { msg >> planetList[i]; + if(planetList[i] !is null) + planetBucket.add(planetList[i]); + } msg >> cnt; orbitalList.length = cnt; @@ -108,14 +123,38 @@ tidy class RegionObjects : Component_RegionObjects, Savable { msg >> cnt; asteroidList.length = cnt; - for(uint i = 0; i < cnt; ++i) + for(uint i = 0; i < cnt; ++i) { msg >> asteroidList[i]; + if(asteroidList[i] !is null) + asteroidBucket.add(asteroidList[i]); + } if(msg >= SV_0039) { msg >> cnt; anomalyList.length = cnt; - for(uint i = 0; i < cnt; ++i) + for(uint i = 0; i < cnt; ++i) { msg >> anomalyList[i]; + if(anomalyList[i] !is null) + anomalyBucket.add(anomalyList[i]); + } + } + + if(msg >= SV_0163) { + msg >> cnt; + artifactList.length = cnt; + for(uint i = 0; i < cnt; ++i) { + msg >> artifactList[i]; + if(artifactList[i] !is null) + artifactBucket.add(artifactList[i]); + } + + msg >> cnt; + pickupList.length = cnt; + for(uint i = 0; i < cnt; ++i) { + msg >> pickupList[i]; + if(pickupList[i] !is null) + pickupBucket.add(pickupList[i]); + } } msg >> cnt; @@ -219,6 +258,16 @@ tidy class RegionObjects : Component_RegionObjects, Savable { for(uint i = 0; i < cnt; ++i) msg << anomalyList[i]; + cnt = artifactList.length; + msg << cnt; + for(uint i = 0; i < cnt; ++i) + msg << artifactList[i]; + + cnt = pickupList.length; + msg << cnt; + for(uint i = 0; i < cnt; ++i) + msg << pickupList[i]; + cnt = shipyardList.length; msg << cnt; for(uint i = 0; i < cnt; ++i) @@ -943,33 +992,33 @@ tidy class RegionObjects : Component_RegionObjects, Savable { } uint get_planetCount() const { - return planetList.length; + return planetBucket.length; } Planet@ get_planets(uint index) const { - if(index >= planetList.length) + if(index >= planetBucket.length) return null; - return planetList[index]; + return planetBucket[index]; } uint get_anomalyCount() const { - return anomalyList.length; + return anomalyBucket.length; } Anomaly@ get_anomalies(uint index) const { - if(index >= anomalyList.length) + if(index >= anomalyBucket.length) return null; - return anomalyList[index]; + return anomalyBucket[index]; } uint get_asteroidCount() const { - return asteroidList.length; + return asteroidBucket.length; } Asteroid@ get_asteroids(uint index) const { - if(index >= asteroidList.length) + if(index >= asteroidBucket.length) return null; - return asteroidList[index]; + return asteroidBucket[index]; } void castOnRandomAsteroid(Object@ obj, int ablId) { @@ -1370,13 +1419,13 @@ tidy class RegionObjects : Component_RegionObjects, Savable { } uint get_starCount() const { - return starList.length; + return starBucket.length; } Star@ get_stars(uint index) const { - if(index >= starList.length) + if(index >= starBucket.length) return null; - return starList[index]; + return starBucket[index]; } double get_starTemperature() const { @@ -1388,32 +1437,28 @@ tidy class RegionObjects : Component_RegionObjects, Savable { } void getPlanets() { - for(uint i = 0, cnt = planetList.length; i < cnt; ++i) - yield(planetList[i]); + for(uint i = 0, cnt = planetBucket.length; i < cnt; ++i) + yield(planetBucket[i]); } void getPickups() { - for(uint i = 0, cnt = objectList.length; i < cnt; ++i) { - if(objectList[i].isPickup) - yield(objectList[i]); - } + for(uint i = 0, cnt = pickupBucket.length; i < cnt; ++i) + yield(pickupBucket[i]); } void getAsteroids() { - for(uint i = 0, cnt = asteroidList.length; i < cnt; ++i) - yield(asteroidList[i]); + for(uint i = 0, cnt = asteroidBucket.length; i < cnt; ++i) + yield(asteroidBucket[i]); } void getAnomalies() { - for(uint i = 0, cnt = anomalyList.length; i < cnt; ++i) - yield(anomalyList[i]); + for(uint i = 0, cnt = anomalyBucket.length; i < cnt; ++i) + yield(anomalyBucket[i]); } void getArtifacts() { - for(uint i = 0, cnt = objectList.length; i < cnt; ++i) { - if(objectList[i].isArtifact) - yield(objectList[i]); - } + for(uint i = 0, cnt = artifactBucket.length; i < cnt; ++i) + yield(artifactBucket[i]); } int getStrength(Empire@ emp) const { @@ -1676,54 +1721,76 @@ tidy class RegionObjects : Component_RegionObjects, Savable { eff.disable(region, obj); } - Ship@ ship = cast(obj); - if(ship !is null) { - auto@ dsg = ship.blueprint.design; - if(obj.owner !is null && obj.owner.valid && ship.hasLeaderAI) { - int value = round(dsg.size); - strengths[obj.owner.index] -= value; + switch(obj.type) + { + case OT_Ship: + { + Ship@ ship = cast(obj); + auto@ dsg = ship.blueprint.design; + if(obj.owner !is null && obj.owner.valid && ship.hasLeaderAI) { + int value = round(dsg.size); + strengths[obj.owner.index] -= value; + } + calculateShips(region); } - calculateShips(region); - } - else { - Planet@ pl = cast(obj); - if(pl !is null) { + break; + case OT_Planet: + { + Planet@ pl = cast(obj); planetList.remove(pl); + planetBucket.remove(pl); if(obj.owner !is null && obj.owner.valid) planetCounts[obj.owner.index] -= 1; calculatePlanets(region); } - else { - //Remove from stars + break; + case OT_Star: + { Star@ star = cast(obj); - if(star !is null) { - starList.remove(star); - StarTemperature -= star.temperature; - if(starList.length != 0) - StarRadius = starList[0].radius; - else - StarRadius = 0; - } - else { - Orbital@ orbital = cast(obj); - if(orbital !is null) { - orbitalList.remove(orbital); - calculateTradeAccess(region); - } - else { - Asteroid@ roid = cast(obj); - if(roid !is null) { - asteroidList.remove(roid); - } - else { - Anomaly@ anomaly = cast(obj); - if(anomaly !is null) { - anomalyList.remove(anomaly); - } - } - } - } + starList.remove(star); + starBucket.remove(star); + StarTemperature -= star.temperature; + if(starList.length != 0) + StarRadius = starList[0].radius; + else + StarRadius = 0; } + break; + case OT_Orbital: + { + Orbital@ orbital = cast(obj); + orbitalList.remove(orbital); + calculateTradeAccess(region); + } + break; + case OT_Asteroid: + { + Asteroid@ roid = cast(obj); + asteroidList.remove(roid); + asteroidBucket.remove(roid); + } + break; + case OT_Anomaly: + { + Anomaly@ anomaly = cast(obj); + anomalyList.remove(anomaly); + anomalyBucket.remove(anomaly); + } + break; + case OT_Pickup: + { + Pickup@ pickup = cast(obj); + pickupList.remove(pickup); + pickupBucket.remove(pickup); + } + break; + case OT_Artifact: + { + Artifact@ artifact = cast(obj); + artifactList.remove(artifact); + artifactBucket.remove(artifact); + } + break; } //Handle shipyards @@ -1742,58 +1809,81 @@ tidy class RegionObjects : Component_RegionObjects, Savable { void enterRegion(Object& thisObj, Object& obj) { Region@ region = cast(thisObj); - Ship@ ship = cast(obj); - if(ship !is null) { - if(obj.owner !is null && obj.owner.valid && ship.hasLeaderAI) { - auto@ dsg = ship.blueprint.design; - if(dsg !is null) { - int value = round(dsg.size); - strengths[obj.owner.index] += value; + switch(obj.type) + { + case OT_Ship: + { + Ship@ ship = cast(obj); + if(obj.owner !is null && obj.owner.valid && ship.hasLeaderAI) { + auto@ dsg = ship.blueprint.design; + if(dsg !is null) { + int value = round(dsg.size); + strengths[obj.owner.index] += value; + } } + calculateShips(region); } - calculateShips(region); - } - else { - Planet@ pl = cast(obj); - if(pl !is null) { + break; + case OT_Planet: + { + Planet@ pl = cast(obj); planetList.insertLast(pl); + planetBucket.add(pl); if(obj.owner !is null && obj.owner.valid) planetCounts[obj.owner.index] += 1; calculatePlanets(region); } - else { + break; + case OT_Star: + { Star@ star = cast(obj); - if(star !is null) { - starList.insertLast(star); - StarTemperature += star.temperature; - if(starList.length != 0) - StarRadius = starList[0].radius; - else - StarRadius = 0; - } - else { - Orbital@ orbital = cast(obj); - if(orbital !is null) { - orbitalList.insertLast(orbital); - /*int value = orbital.MilitaryValue;*/ - /*if(obj.owner !is null && obj.owner.valid)*/ - /* strengths[obj.owner.index] += value;*/ - calculateTradeAccess(region); - } - else { - Asteroid@ roid = cast(obj); - if(roid !is null) { - asteroidList.insertLast(roid); - } - else { - Anomaly@ anomaly = cast(obj); - if(anomaly !is null) { - anomalyList.insertLast(anomaly); - } - } - } - } + starList.insertLast(star); + starBucket.add(star); + StarTemperature += star.temperature; + if(starList.length != 0) + StarRadius = starList[0].radius; + else + StarRadius = 0; } + break; + case OT_Orbital: + { + Orbital@ orbital = cast(obj); + orbitalList.insertLast(orbital); + /*int value = orbital.MilitaryValue;*/ + /*if(obj.owner !is null && obj.owner.valid)*/ + /* strengths[obj.owner.index] += value;*/ + calculateTradeAccess(region); + } + break; + case OT_Asteroid: + { + Asteroid@ roid = cast(obj); + asteroidList.insertLast(roid); + asteroidBucket.add(roid); + } + break; + case OT_Anomaly: + { + Anomaly@ anomaly = cast(obj); + anomalyList.insertLast(anomaly); + anomalyBucket.add(anomaly); + } + break; + case OT_Pickup: + { + Pickup@ pickup = cast(obj); + pickupList.insertLast(pickup); + pickupBucket.add(pickup); + } + break; + case OT_Artifact: + { + Artifact@ artifact = cast(obj); + artifactList.insertLast(artifact); + artifactBucket.add(artifact); + } + break; } //Add to all objects