Index: binaries/data/mods/public/gui/credits/texts/programming.json =================================================================== --- binaries/data/mods/public/gui/credits/texts/programming.json +++ binaries/data/mods/public/gui/credits/texts/programming.json @@ -175,6 +175,7 @@ { "nick": "MattDoerksen", "name": "Matt Doerksen" }, { "nick": "mattlott", "name": "Matt Lott" }, { "nick": "maveric", "name": "Anton Protko" }, + { "nick": "Mercury", "name": "Alexander Gilliland"}, { "nick": "Micnasty", "name": "Travis Gorkin" }, { "name": "MikoĊ‚aj \"Bajter\" Korcz" }, { "nick": "mimo" }, Index: binaries/data/mods/public/simulation/components/GarrisonHolder.js =================================================================== --- binaries/data/mods/public/simulation/components/GarrisonHolder.js +++ binaries/data/mods/public/simulation/components/GarrisonHolder.js @@ -311,8 +311,8 @@ */ GarrisonHolder.prototype.OnHealthChanged = function(msg) { - if (!this.HasEnoughHealth() && this.entities.length) - this.EjectOrKill(this.entities.slice()); + if (this.entities.length && !this.HasEnoughHealth()) + this.EjectOrKill(this.entities.slice(), msg.changeSource, msg.changeSourceOwner); }; GarrisonHolder.prototype.HasEnoughHealth = function() @@ -398,7 +398,7 @@ let entities = this.entities.filter(ent => msg.to == INVALID_PLAYER || !IsOwnedByMutualAllyOfEntity(this.entity, ent)); if (entities.length) - this.EjectOrKill(entities); + this.EjectOrKill(entities, msg.entity, msg.to); return; } @@ -406,7 +406,7 @@ // or on some of its garrisoned units let entityIndex = this.entities.indexOf(msg.entity); if (entityIndex != -1 && (msg.to == INVALID_PLAYER || !IsOwnedByMutualAllyOfEntity(this.entity, msg.entity))) - this.EjectOrKill([msg.entity]); + this.EjectOrKill([msg.entity], this.entity, msg.to); }; /** @@ -436,15 +436,20 @@ */ GarrisonHolder.prototype.OnDiplomacyChanged = function() { - this.EjectOrKill(this.entities.filter(ent => !IsOwnedByMutualAllyOfEntity(this.entity, ent))); + this.EjectOrKill(this.entities.filter(ent => !IsOwnedByMutualAllyOfEntity(this.entity, ent)), this.entity); }; /** * Eject or kill a garrisoned unit which can no more be garrisoned * (garrisonholder's health too small or ownership changed). */ -GarrisonHolder.prototype.EjectOrKill = function(entities) +GarrisonHolder.prototype.EjectOrKill = function(entities, changeSource = INVALID_ENTITY, changeSourceOwner = INVALID_PLAYER) { +/** + * @param entities an array of entities to eject + * @param changeSource the source unit of the ejection + * @param changeSourceOwner the player id of the owner of the changeSource, optional + */ let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); // Eject the units which can be ejected (if not in world, it generally means this holder // is inside a holder which kills its entities, so do not eject) @@ -464,7 +469,7 @@ continue; let cmpHealth = Engine.QueryInterface(entity, IID_Health); if (cmpHealth) - cmpHealth.Kill(); + cmpHealth.KilledBy(changeSource, changeSourceOwner); else Engine.DestroyEntity(entity); this.entities.splice(entityIndex, 1); @@ -532,7 +537,7 @@ if (msg.valueNames.indexOf("GarrisonHolder/List/_string") !== -1) { this.allowedClasses = ApplyValueModificationsToEntity("GarrisonHolder/List/_string", this.template.List._string, this.entity); - this.EjectOrKill(this.entities.filter(entity => !this.IsAllowedToBeGarrisoned(entity))); + this.EjectOrKill(this.entities.filter(entity => !this.IsAllowedToBeGarrisoned(entity)), this.entity); } if (msg.valueNames.indexOf("GarrisonHolder/BuffHeal") === -1) 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 @@ -190,7 +190,7 @@ if (!amount || !this.hitpoints) return { "healthChange": 0 }; - let change = this.Reduce(amount); + const change = this.Reduce(amount, attacker, attackerOwner); let cmpLoot = Engine.QueryInterface(this.entity, IID_Loot); if (cmpLoot && cmpLoot.GetXp() > 0 && change.healthChange < 0) @@ -234,9 +234,11 @@ /** * @param {number} amount - The amount of hitpoints to substract. Kills the entity if required. + * @param {entity} attacker - The unit which attacked + * @param {number} attackerOwner - The player id of the owner of the attacker * @return {{ healthChange:number }} - Number of health points lost. */ -Health.prototype.Reduce = function(amount) +Health.prototype.Reduce = function(amount, attacker, attackerOwner) { // If we are dead, do not do anything // (The entity will exist a little while after calling DestroyEntity so this @@ -255,7 +257,7 @@ if (amount >= this.hitpoints) { this.hitpoints = 0; - this.RegisterHealthChanged(oldHitpoints); + this.RegisterHealthChanged(oldHitpoints, attacker, attackerOwner); this.HandleDeath(); return { "healthChange": -oldHitpoints }; } @@ -269,7 +271,7 @@ } this.hitpoints -= amount; - this.RegisterHealthChanged(oldHitpoints); + this.RegisterHealthChanged(oldHitpoints, attacker, attackerOwner); return { "healthChange": this.hitpoints - oldHitpoints }; }; @@ -492,11 +494,17 @@ this.RecalculateValues(); }; -Health.prototype.RegisterHealthChanged = function(from) +Health.prototype.RegisterHealthChanged = function(from, changeSource, changeSourceOwner) { this.CheckRegenTimer(); this.UpdateActor(); - Engine.PostMessage(this.entity, MT_HealthChanged, { "from": from, "to": this.hitpoints }); + const msg = { "from": from, "to": this.hitpoints }; + if (changeSource) + { + msg.changeSource = changeSource; + msg.changeSourceOwner = changeSourceOwner; + } + Engine.PostMessage(this.entity, MT_HealthChanged, msg); }; function HealthMirage() {}