Index: binaries/data/mods/public/art/actors/units/britons/chariot_javelinist_c_m.xml =================================================================== --- binaries/data/mods/public/art/actors/units/britons/chariot_javelinist_c_m.xml +++ binaries/data/mods/public/art/actors/units/britons/chariot_javelinist_c_m.xml @@ -18,7 +18,6 @@ - Index: binaries/data/mods/public/art/actors/units/britons/hero_chariot_javelinist_boudicca_m.xml =================================================================== --- binaries/data/mods/public/art/actors/units/britons/hero_chariot_javelinist_boudicca_m.xml +++ binaries/data/mods/public/art/actors/units/britons/hero_chariot_javelinist_boudicca_m.xml @@ -17,7 +17,6 @@ - Index: binaries/data/mods/public/gui/session/unit_actions.js =================================================================== --- binaries/data/mods/public/gui/session/unit_actions.js +++ binaries/data/mods/public/gui/session/unit_actions.js @@ -1321,7 +1321,7 @@ continue; if (allowedPlayersCheck([entState], ["Player"])) - count += entState.turretHolder.turretPoints.filter(turretPoint => turretPoint.entity).length; + count += entState.turretHolder.turretPoints.filter(turretPoint => turretPoint.entity && turretPoint.ejectable).length; else for (let turretPoint of entState.turretHolder.turretPoints) if (turretPoint.entity && allowedPlayersCheck([GetEntityState(turretPoint.entity)], ["Player"])) @@ -1443,7 +1443,8 @@ "getInfo": function(entStates) { if (entStates.every(entState => !entState.turretable || - entState.turretable.holder == INVALID_ENTITY)) + entState.turretable.holder == INVALID_ENTITY || + !entState.turretable.ejectable)) return false; return { @@ -1460,7 +1461,8 @@ Engine.PostNetworkCommand({ "type": "leave-turret", "entities": entStates.filter(entState => entState.turretable && - entState.turretable.holder != INVALID_ENTITY).map(entState => entState.id) + entState.turretable.holder != INVALID_ENTITY || + !entState.turretable.ejectable).map(entState => entState.id) }); }, "allowedPlayers": ["Player"] Index: binaries/data/mods/public/simulation/components/GuiInterface.js =================================================================== --- binaries/data/mods/public/simulation/components/GuiInterface.js +++ binaries/data/mods/public/simulation/components/GuiInterface.js @@ -391,6 +391,7 @@ let cmpTurretable = Engine.QueryInterface(ent, IID_Turretable); if (cmpTurretable) ret.turretable = { + "ejectable": cmpTurretable.IsEjectable(), "holder": cmpTurretable.HolderID() }; Index: binaries/data/mods/public/simulation/components/Health.js =================================================================== --- binaries/data/mods/public/simulation/components/Health.js +++ binaries/data/mods/public/simulation/components/Health.js @@ -134,8 +134,7 @@ if (this.GetIdleRegenRate() != 0) { let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); - if (cmpUnitAI && (cmpUnitAI.IsIdle() || - cmpUnitAI.GetGarrisonHolder() != INVALID_ENTITY && !cmpUnitAI.IsTurret())) + if (cmpUnitAI && cmpUnitAI.IsIdle()) regen += this.GetIdleRegenRate(); } Index: binaries/data/mods/public/simulation/components/TurretHolder.js =================================================================== --- binaries/data/mods/public/simulation/components/TurretHolder.js +++ binaries/data/mods/public/simulation/components/TurretHolder.js @@ -19,11 +19,41 @@ }, "allowedClasses": points[point].AllowedClasses, "angle": points[point].Angle ? +points[point].Angle * Math.PI / 180 : null, - "entity": null + "entity": null, + "template": points[point].Template, + "ejectable": "Ejectable" in points[point] ? points[point].Ejectable == "true" : true }); } /** + * Add a subunit as specified in the template. + * This function creates an entity and places it on the turret point. + * + * @param {Object} turretPoint - A turret point to (re)create the predefined subunit for. + * + * @return {boolean} - Whether the turret creation has succeeded. + */ + CreateSubunit(turretPointName) + { + let turretPoint = this.TurretPointByName(turretPointName); + if (!turretPoint || turretPoint.entity || this.initTurrets && this.initTurrets.has(turretPointName)) + return false; + + let ent = Engine.AddEntity(turretPoint.template); + + let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); + if (cmpOwnership) + { + let cmpEntOwnership = Engine.QueryInterface(ent, IID_Ownership); + if (cmpEntOwnership) + cmpEntOwnership.SetOwner(cmpOwnership.GetOwner()); + } + + let cmpTurretable = Engine.QueryInterface(ent, IID_Turretable); + return cmpTurretable && cmpTurretable.OccupyTurret(this.entity, turretPoint.name, turretPoint.ejectable) || Engine.DestroyEntity(ent); + } + + /** * @return {Object[]} - An array of the turret points this entity has. */ GetTurretPoints() @@ -37,7 +67,7 @@ * * @return {boolean} - Whether the entity is allowed to occupy the specified turret point. */ - AllowedToOccupyTurret(entity, turretPoint) + AllowedToOccupyTurretPoint(entity, turretPoint) { if (!turretPoint || turretPoint.entity) return false; @@ -58,7 +88,7 @@ */ CanOccupy(entity) { - return !!this.turretPoints.find(turretPoint => this.AllowedToOccupyTurret(entity, turretPoint)); + return !!this.turretPoints.find(turretPoint => this.AllowedToOccupyTurretPoint(entity, turretPoint)); } /** @@ -68,7 +98,7 @@ * * @return {boolean} - Whether the occupation was successful. */ - OccupyTurret(entity, requestedTurretPoint) + OccupyTurretPoint(entity, requestedTurretPoint) { let cmpPositionOccupant = Engine.QueryInterface(entity, IID_Position); if (!cmpPositionOccupant) @@ -78,17 +108,17 @@ if (!cmpPositionSelf) return false; - if (this.OccupiesTurret(entity)) + if (this.OccupiesTurretPoint(entity)) return false; let turretPoint; if (requestedTurretPoint) { - if (this.AllowedToOccupyTurret(entity, requestedTurretPoint)) + if (this.AllowedToOccupyTurretPoint(entity, requestedTurretPoint)) turretPoint = requestedTurretPoint; } else - turretPoint = this.turretPoints.find(turret => !turret.entity && this.AllowedToOccupyTurret(entity, turret)); + turretPoint = this.turretPoints.find(turret => !turret.entity && this.AllowedToOccupyTurretPoint(entity, turret)); if (!turretPoint) return false; @@ -121,9 +151,18 @@ * @param {String} turretName - The name of the turret point to occupy. * @return {boolean} - Whether the occupation has succeeded. */ - OccupyNamedTurret(entity, turretName) + OccupyNamedTurretPoint(entity, turretName) { - return this.OccupyTurret(entity, this.turretPoints.find(turret => turret.name == turretName)); + return this.OccupyTurretPoint(entity, this.TurretPointByName(turretName)); + } + + /** + * @param {string} turretPointName - The name of the requested turret point. + * @return {Object} - The requested turret point. + */ + TurretPointByName(turretPointName) + { + return this.turretPoints.find(turret => turret.name == turretPointName); } /** @@ -133,7 +172,7 @@ * * @return {boolean} - Whether the entity was occupying a/the turret before. */ - LeaveTurret(entity, requestedTurretPoint) + LeaveTurretPoint(entity, requestedTurretPoint) { let turretPoint; if (requestedTurretPoint) @@ -142,17 +181,13 @@ turretPoint = requestedTurretPoint; } else - turretPoint = this.turretPoints.find(turret => turret.entity == entity); + turretPoint = this.GetOccupiedTurretPoint(entity); - if (!turretPoint) + if (!turretPoint || !turretPoint.ejectable) return false; turretPoint.entity = null; - let cmpPositionEntity = Engine.QueryInterface(entity, IID_Position); - if (cmpPositionEntity) - cmpPositionEntity.SetTurretParent(INVALID_ENTITY, new Vector3D()); - Engine.PostMessage(this.entity, MT_TurretsChanged, { "added": [], "removed": [entity] @@ -167,17 +202,17 @@ * * @return {boolean} - Whether the entity is positioned on a turret of this entity. */ - OccupiesTurret(entity, requestedTurretPoint) + OccupiesTurretPoint(entity, requestedTurretPoint) { return requestedTurretPoint ? requestedTurretPoint.entity == entity : - this.turretPoints.some(turretPoint => turretPoint.entity == entity); + !!this.GetOccupiedTurretPoint(entity); } /** * @param {number} entity - The entity's id. * @return {Object} - The turret this entity is positioned on, if applicable. */ - GetOccupiedTurret(entity) + GetOccupiedTurretPoint(entity) { return this.turretPoints.find(turretPoint => turretPoint.entity == entity); } @@ -186,9 +221,9 @@ * @param {number} entity - The entity's id. * @return {Object} - The turret this entity is positioned on, if applicable. */ - GetOccupiedTurretName(entity) + GetOccupiedTurretPointName(entity) { - let turret = this.GetOccupiedTurret(entity); + let turret = this.GetOccupiedTurretPoint(entity); return turret ? turret.name : ""; } @@ -306,9 +341,12 @@ return; for (let [turretPointName, entity] of this.initTurrets) - if (!this.OccupyNamedTurret(entity, turretPointName)) + { + let cmpTurretable = Engine.QueryInterface(entity, IID_Turretable); + if (!cmpTurretable || !cmpTurretable.OccupyTurret(this.entity, turretPointName, this.TurretPointByName(turretPointName).ejectable)) warn("Entity " + entity + " could not occupy the turret point " + turretPointName + " of turret holder " + this.entity + "."); + } delete this.initTurrets; } @@ -323,7 +361,7 @@ let cmpTurretable = Engine.QueryInterface(entity, IID_Turretable); if (!cmpTurretable) continue; - let currentPoint = this.GetOccupiedTurretName(entity); + let currentPoint = this.GetOccupiedTurretPointName(entity); cmpTurretable.LeaveTurret(true); cmpTurretable.OccupyTurret(msg.newentity, currentPoint); } @@ -334,19 +372,36 @@ */ OnOwnershipChanged(msg) { - let entities = this.GetEntities(); - if (!entities.length) + if (msg.to === INVALID_PLAYER) + { + this.EjectOrKill(this.GetEntities()); return; - - if (msg.to == INVALID_PLAYER) - this.EjectOrKill(entities); - else - for (let entity of entities.filter(entity => !IsOwnedByMutualAllyOfEntity(entity, this.entity))) + } + for (let point of this.turretPoints) + { + // If we were created, create any subunits now. + // This has to be done here (instead of on Init) + // for Ownership ought to be initialised. + if (point.template && msg.from === INVALID_PLAYER) { - let cmpTurretable = Engine.QueryInterface(entity, IID_Turretable); + this.CreateSubunit(point.name); + continue; + } + if (!point.entity) + continue; + if (!point.ejectable) + { + let cmpTurretOwnership = Engine.QueryInterface(point.entity, IID_Ownership); + if (cmpTurretOwnership) + cmpTurretOwnership.SetOwner(msg.to); + } + else if (!IsOwnedByMutualAllyOfEntity(point.entity, this.entity)) + { + let cmpTurretable = Engine.QueryInterface(point.entity, IID_Turretable); if (cmpTurretable) cmpTurretable.LeaveTurret(); } + } } } @@ -366,6 +421,16 @@ "" + "" + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + "" + "" + "tokens" + Index: binaries/data/mods/public/simulation/components/Turretable.js =================================================================== --- binaries/data/mods/public/simulation/components/Turretable.js +++ binaries/data/mods/public/simulation/components/Turretable.js @@ -24,6 +24,14 @@ }; /** + * @return {boolean} - Whether we can leave the turret point. + */ +Turretable.prototype.IsEjectable = function() +{ + return this.ejectable; +}; + +/** * @param {number} target - The entity ID to check. * @return {boolean} - Whether we can occupy the turret. */ @@ -39,18 +47,21 @@ /** * @param {number} target - The entity ID of the entity this entity is being turreted on. * @param {string} turretPointName - Optionally the turret point name to occupy. + * @param {boolean} ejectable - Whether we can leave this turret point (e.g. false for a tank turret). + * * @return {boolean} - Whether occupying succeeded. */ -Turretable.prototype.OccupyTurret = function(target, turretPointName = "") +Turretable.prototype.OccupyTurret = function(target, turretPointName = "", ejectabe = true) { if (!this.CanOccupy(target)) return false; let cmpTurretHolder = Engine.QueryInterface(target, IID_TurretHolder); - if (!cmpTurretHolder || !cmpTurretHolder.OccupyNamedTurret(this.entity, turretPointName)) + if (!cmpTurretHolder || !cmpTurretHolder.OccupyNamedTurretPoint(this.entity, turretPointName)) return false; this.holder = target; + this.ejectable = ejectabe; let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); if (cmpUnitAI) @@ -85,12 +96,15 @@ if (!this.holder) return true; + if (!this.ejectable) + return false; + let pos = PositionHelper.GetSpawnPosition(this.holder, this.entity, forced); if (!pos) return false; let cmpTurretHolder = Engine.QueryInterface(this.holder, IID_TurretHolder); - if (!cmpTurretHolder || !cmpTurretHolder.LeaveTurret(this.entity)) + if (!cmpTurretHolder || !cmpTurretHolder.LeaveTurretPoint(this.entity)) return false; let cmpUnitMotionEntity = Engine.QueryInterface(this.entity, IID_UnitMotion); @@ -100,6 +114,7 @@ let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); if (cmpPosition) { + cmpPosition.SetTurretParent(INVALID_ENTITY, new Vector3D()); cmpPosition.JumpTo(pos.x, pos.z); cmpPosition.SetHeightOffset(0); } @@ -131,6 +146,7 @@ cmpRallyPoint.OrderToRallyPoint(this.entity, ["occupy-turret"]); delete this.holder; + delete this.ejectable; return true; }; @@ -144,7 +160,7 @@ return; let holder = this.holder; - let currentPoint = cmpTurretHolder.GetOccupiedTurretName(this.entity); + let currentPoint = cmpTurretHolder.GetOccupiedTurretPointName(this.entity); this.LeaveTurret(true); let cmpTurretableNew = Engine.QueryInterface(msg.newentity, IID_Turretable); if (cmpTurretableNew) Index: binaries/data/mods/public/simulation/components/UnitAI.js =================================================================== --- binaries/data/mods/public/simulation/components/UnitAI.js +++ binaries/data/mods/public/simulation/components/UnitAI.js @@ -3547,15 +3547,6 @@ this.SetMobile(); }; -UnitAI.prototype.GetGarrisonHolder = function() -{ - if (!this.isGarrisoned) - return INVALID_ENTITY; - - let cmpGarrisonable = Engine.QueryInterface(this.entity, IID_Garrisonable); - return cmpGarrisonable ? cmpGarrisonable.HolderID() : INVALID_ENTITY; -}; - UnitAI.prototype.ShouldRespondToEndOfAlert = function() { return !this.orderQueue.length || this.orderQueue[0].type == "Garrison"; Index: binaries/data/mods/public/simulation/components/tests/test_TurretHolder.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_TurretHolder.js +++ binaries/data/mods/public/simulation/components/tests/test_TurretHolder.js @@ -91,34 +91,34 @@ }); // Test visible garrisoning restrictions. -TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(siegeEngineID, cmpTurretHolder.turretPoints[0]), true); -TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(siegeEngineID, cmpTurretHolder.turretPoints[1]), true); -TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(siegeEngineID, cmpTurretHolder.turretPoints[2]), true); -TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(archerID, cmpTurretHolder.turretPoints[0]), true); -TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(archerID, cmpTurretHolder.turretPoints[1]), false); -TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(archerID, cmpTurretHolder.turretPoints[2]), true); -TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(cavID, cmpTurretHolder.turretPoints[0]), true); -TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(cavID, cmpTurretHolder.turretPoints[1]), false); -TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(cavID, cmpTurretHolder.turretPoints[2]), true); -TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(infID, cmpTurretHolder.turretPoints[0]), true); -TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(infID, cmpTurretHolder.turretPoints[1]), false); -TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurret(infID, cmpTurretHolder.turretPoints[2]), false); +TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurretPoint(siegeEngineID, cmpTurretHolder.turretPoints[0]), true); +TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurretPoint(siegeEngineID, cmpTurretHolder.turretPoints[1]), true); +TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurretPoint(siegeEngineID, cmpTurretHolder.turretPoints[2]), true); +TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurretPoint(archerID, cmpTurretHolder.turretPoints[0]), true); +TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurretPoint(archerID, cmpTurretHolder.turretPoints[1]), false); +TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurretPoint(archerID, cmpTurretHolder.turretPoints[2]), true); +TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurretPoint(cavID, cmpTurretHolder.turretPoints[0]), true); +TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurretPoint(cavID, cmpTurretHolder.turretPoints[1]), false); +TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurretPoint(cavID, cmpTurretHolder.turretPoints[2]), true); +TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurretPoint(infID, cmpTurretHolder.turretPoints[0]), true); +TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurretPoint(infID, cmpTurretHolder.turretPoints[1]), false); +TS_ASSERT_EQUALS(cmpTurretHolder.AllowedToOccupyTurretPoint(infID, cmpTurretHolder.turretPoints[2]), false); // Test that one cannot leave a turret that is not occupied. -TS_ASSERT(!cmpTurretHolder.LeaveTurret(archerID)); +TS_ASSERT(!cmpTurretHolder.LeaveTurretPoint(archerID)); // Test occupying a turret. -TS_ASSERT(!cmpTurretHolder.OccupiesTurret(archerID)); -TS_ASSERT(cmpTurretHolder.OccupyTurret(archerID)); -TS_ASSERT(cmpTurretHolder.OccupiesTurret(archerID)); +TS_ASSERT(!cmpTurretHolder.OccupiesTurretPoint(archerID)); +TS_ASSERT(cmpTurretHolder.OccupyTurretPoint(archerID)); +TS_ASSERT(cmpTurretHolder.OccupiesTurretPoint(archerID)); // We're not occupying a turret that we can't occupy. -TS_ASSERT(!cmpTurretHolder.OccupiesTurret(archerID, cmpTurretHolder.turretPoints[1])); -TS_ASSERT(!cmpTurretHolder.OccupyTurret(cavID, cmpTurretHolder.turretPoints[1])); -TS_ASSERT(!cmpTurretHolder.OccupyTurret(cavID, cmpTurretHolder.turretPoints[0])); -TS_ASSERT(cmpTurretHolder.OccupyTurret(cavID, cmpTurretHolder.turretPoints[2])); +TS_ASSERT(!cmpTurretHolder.OccupiesTurretPoint(archerID, cmpTurretHolder.turretPoints[1])); +TS_ASSERT(!cmpTurretHolder.OccupyTurretPoint(cavID, cmpTurretHolder.turretPoints[1])); +TS_ASSERT(!cmpTurretHolder.OccupyTurretPoint(cavID, cmpTurretHolder.turretPoints[0])); +TS_ASSERT(cmpTurretHolder.OccupyTurretPoint(cavID, cmpTurretHolder.turretPoints[2])); // Leave turrets. -TS_ASSERT(cmpTurretHolder.LeaveTurret(archerID)); -TS_ASSERT(!cmpTurretHolder.LeaveTurret(cavID, cmpTurretHolder.turretPoints[1])); -TS_ASSERT(cmpTurretHolder.LeaveTurret(cavID, cmpTurretHolder.turretPoints[2])); +TS_ASSERT(cmpTurretHolder.LeaveTurretPoint(archerID)); +TS_ASSERT(!cmpTurretHolder.LeaveTurretPoint(cavID, cmpTurretHolder.turretPoints[1])); +TS_ASSERT(cmpTurretHolder.LeaveTurretPoint(cavID, cmpTurretHolder.turretPoints[2])); Index: binaries/data/mods/public/simulation/components/tests/test_Turrets.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Turrets.js +++ binaries/data/mods/public/simulation/components/tests/test_Turrets.js @@ -87,7 +87,7 @@ TS_ASSERT(cmpTurretable.OccupyTurret(holder)); TS_ASSERT_UNEVAL_EQUALS(cmpTurretHolder.GetEntities(), [turret]); -TS_ASSERT(cmpTurretHolder.OccupiesTurret(turret)); +TS_ASSERT(cmpTurretHolder.OccupiesTurretPoint(turret)); TS_ASSERT(cmpTurretable.LeaveTurret()); TS_ASSERT_UNEVAL_EQUALS(cmpTurretHolder.GetEntities(), []); @@ -98,12 +98,12 @@ TS_ASSERT(cmpTurretableNew.OccupyTurret(holder)); TS_ASSERT(cmpTurretable.OccupyTurret(holder)); TS_ASSERT(cmpTurretableNew.LeaveTurret()); -let previousTurret = cmpTurretHolder.GetOccupiedTurretName(turret); +let previousTurret = cmpTurretHolder.GetOccupiedTurretPointName(turret); cmpTurretable.OnEntityRenamed({ "entity": turret, "newentity": newTurret }); -let newTurretPos = cmpTurretHolder.GetOccupiedTurretName(newTurret); +let newTurretPos = cmpTurretHolder.GetOccupiedTurretPointName(newTurret); TS_ASSERT_UNEVAL_EQUALS(newTurretPos, previousTurret); TS_ASSERT(cmpTurretableNew.LeaveTurret()); Index: binaries/data/mods/public/simulation/helpers/Transform.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Transform.js +++ binaries/data/mods/public/simulation/helpers/Transform.js @@ -67,7 +67,7 @@ cmpNewUnitAI.SetHeldPosition(pos.x, pos.z); if (cmpUnitAI.GetStanceName()) cmpNewUnitAI.SwitchToStance(cmpUnitAI.GetStanceName()); - if (cmpUnitAI.GetGarrisonHolder() != INVALID_ENTITY) + if (cmpUnitAI.isGarrisoned) cmpNewUnitAI.SetGarrisoned(); cmpNewUnitAI.AddOrders(cmpUnitAI.GetOrders()); if (cmpUnitAI.IsGuardOf()) Index: binaries/data/mods/public/simulation/templates/units/brit/champion_chariot.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/brit/champion_chariot.xml +++ binaries/data/mods/public/simulation/templates/units/brit/champion_chariot.xml @@ -1,5 +1,6 @@ + 6.0 @@ -13,6 +14,18 @@ units/brit_champion_chariot.png unlock_champion_chariots + + + + + true + 0 + 1.4 + -2.5 + 0 + + + units/britons/chariot_javelinist_c_m.xml Index: binaries/data/mods/public/simulation/templates/units/brit/hero_boudicca.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/brit/hero_boudicca.xml +++ binaries/data/mods/public/simulation/templates/units/brit/hero_boudicca.xml @@ -1,8 +1,6 @@ - - units/heroes/brit_hero_boudicca - + 6.0 @@ -12,7 +10,7 @@ female Boudicca Boudica - Chariot + Chariot -Hero units/brit_hero_boudicca.png @@ -22,6 +20,18 @@ + + + + + false + 0 + 1.4 + -2.5 + 0 + + + units/britons/hero_chariot_javelinist_boudicca_m.xml Index: binaries/data/mods/public/simulation/templates/units/brit/hero_boudicca_sword.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/brit/hero_boudicca_sword.xml +++ binaries/data/mods/public/simulation/templates/units/brit/hero_boudicca_sword.xml @@ -10,6 +10,7 @@ female units/brit_hero_boudicca.png + units/britons/hero_infantry_swordsman_boudicca.xml Index: source/graphics/MapReader.cpp =================================================================== --- source/graphics/MapReader.cpp +++ source/graphics/MapReader.cpp @@ -1058,10 +1058,6 @@ // TODO: other parts of the position } - CmpPtr cmpOwnership(sim, ent); - if (cmpOwnership) - cmpOwnership->SetOwner(PlayerID); - if (!Garrison.empty()) { CmpPtr cmpGarrisonHolder(sim, ent); @@ -1071,6 +1067,8 @@ LOGERROR("CXMLMapReader::ReadEntities() entity '%d' of player '%d' has no GarrisonHolder component and thus cannot garrison units.", ent, PlayerID); } + // Needs to be before ownership changes to prevent initialising + // subunits too soon. if (!Turrets.empty()) { CmpPtr cmpTurretHolder(sim, ent); @@ -1080,6 +1078,10 @@ LOGERROR("CXMLMapReader::ReadEntities() entity '%d' of player '%d' has no TurretHolder component and thus cannot use turrets.", ent, PlayerID); } + CmpPtr cmpOwnership(sim, ent); + if (cmpOwnership) + cmpOwnership->SetOwner(PlayerID); + CmpPtr cmpObstruction(sim, ent); if (cmpObstruction) { Index: source/simulation2/components/CCmpPosition.cpp =================================================================== --- source/simulation2/components/CCmpPosition.cpp +++ source/simulation2/components/CCmpPosition.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,6 +21,8 @@ #include "ICmpPosition.h" #include "simulation2/MessageTypes.h" +#include "simulation2/serialization/SerializeTemplates.h" +#include "simulation2/serialization/SerializedTypes.h" #include "ICmpTerrain.h" #include "ICmpTerritoryManager.h" @@ -228,6 +230,7 @@ serialize.NumberFixed_Unbounded("y", m_TurretPosition.Y); serialize.NumberFixed_Unbounded("z", m_TurretPosition.Z); } + Serializer(serialize, "turrets", m_Turrets); } virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) @@ -265,6 +268,7 @@ deserialize.NumberFixed_Unbounded("y", m_TurretPosition.Y); deserialize.NumberFixed_Unbounded("z", m_TurretPosition.Z); } + Serializer(deserialize, "turrets", m_Turrets); if (m_InWorld) UpdateXZRotation(); Index: source/simulation2/components/ICmpTurretHolder.cpp =================================================================== --- source/simulation2/components/ICmpTurretHolder.cpp +++ source/simulation2/components/ICmpTurretHolder.cpp @@ -40,7 +40,7 @@ std::vector entities = m_Script.Call>("GetEntities"); for (entity_id_t entity : entities) turrets.push_back(std::make_pair( - m_Script.Call("GetOccupiedTurretName", entity), + m_Script.Call("GetOccupiedTurretPointName", entity), entity ));