Greetings Cosmoteer Developer Walt,
Whilst attempting to mod in some friendly fire based projectiles, I noticed a rather peculiar occurrence when setting up an AllowFriendlyDamage tag on SimpleHit ShieldDamage. Regardless of the parameters, collisionSize, speed, HitType etc set - the projectile seemed to never actually interact with friendly shields. Bullets would merely pass through unshaped and collide with the generator block for all ships of the same faction of the sourceShip.
After looking at the source, it became quickly apparent why.
In the Cosmoteer.Ships.Parts.Defenses.ArcShield class, there is a method called ValidateShieldHit which checks for bullet collision with the shield and if true conveys the information for the Cosmoteer.Bullets.Hits classes to incur an effect (like damaging it). As part of the three conditionals (not including the default false return on no conditions met) - there is a check to see if the ship with the potentially intersecting shield (base.Ship) CanBeDamagedBy the sourceShip - or the ship which fired the projectile in question. If this check is false, then the function stops there and no collision is calculated.
This is good for performance, bad for our AllowFriendlyDamage.
The problem occurs when you realize Ship.CanBeDamagedBy looks like this:
return ship != this && PlayerIndexes.CanDamage(ship.Metadata.PlayerIndex, this.Metadata.PlayerIndex);
For the less C# inclined, the function returns a boolean (true or false value) based upon two criteria - both of which must be true for it to return true:
1) Is this a different ship from the original ship which fired the projectile?
2) Are the PlayerIndexes (Player 1, Player 2, Junk, Barbarian, etc) of the two ships able to damage each other? [Note, not are they the same - can they damage each other. This is how Barbarians work - their playerIndex is set to be able to damage itself.]
Combining what we know about the two aforementioned classes - one might come to the realization that in the current system friendly shield damage is impossible because collisions are disabled on a global faction level for shields and therefor the Bullet rules are automatically overridden and are therefor useless. (I feel the AllowFriendlyDamage on ShieldHit was added as an afterthought, rather than goal).
Since my easy tools tried to murder my computer upon usage, I can only make a clear suggestion on what can be done about this rather than the preferred exe patch, but essentially it seems there would be little reason not to pass an int through the ValidateShieldHit methods arguments labeled collision - read from the bullet the same as BulletLocation and BulletVelocity - and then pass it through the canBeDamagedBy(sourceShip) method via a modified argument which lead to a switch statement passing the values to a relevant set of logical operands. For instance, if:
0 - default collision (do not collide with friendly or source)
1 - collide with friendly, not source ship
2 - collide with friendly and source
A statement could be written as:
public bool CanBeDamagedBy(Ship ship, int collisionMode)
{
if (ship == null)
{
throw new ArgumentNullException("ship");
}
switch (collisionMode)
{
case 0:
return ship != this && PlayerIndexes.CanDamage(ship.Metadata.PlayerIndex, this.Metadata.PlayerIndex);
break;
case 1:
return ship != this;
break;
case 2:
return true;
break;
}
}
This was the way I was going to test, but alas - HDD failure probably murdered something important in my RE setup. Good tidings pip tally chap g'day.
Apologies for English if hard to understand.
EDIT - Code block difficulty on second switch statement example - apologies for format.