| Scripts/NPC_Equipment_Damage.js | this.name = "NPC_Equipment_Damage";
this.author = "Ngalo";
this.copyright = "CC-BY-NC-SA";
this.description = "Randomly damages NPC equipment, imitating what Oolite does for player-ship internal damage as far as possible.";
this.version = "0.3.0";
"use strict";
this.NPC_equipmentDamagedHandlers = [];
this.startUp = function()
{
	if (worldScripts.ShipConfiguration_NPCShips)
	{
		this.NPC_equipmentDamagedHandlers.push(this._shipconf_equipmentDamaged);
	}
}
this.shipSpawned = function(ship)
{
	// Check whether ship should have eq dmg?
	if (worldScripts.NShields && worldScripts.NShields.$shipHasShields(ship))
	{
		if (!ship.script._NShields_damageHandlers) ship.script._NShields_damageHandlers = [];
		ship.script._NShields_damageHandlers.push(this._NPC_internalDamageWrapper);
	}
	else
	{
		if (ship.isPiloted)
		{
			ship.script.EqDmg_hold_shipTakingDamage = ship.script.shipTakingDamage;
			ship.script.shipTakingDamage = this._NPC_internalDamageWrapper;
		}
	}
	ship.script.EqDmg_serviceLevel = Math.random()*25 + 75; // service level between 75 and 100
}
this._NPC_internalDamageWrapper = function (amount, whom, type)
{
	if (type == "cascade weapon") return;
	if(amount > 0 && this.EqDmg_hold_shipTakingDamage) this.EqDmg_hold_shipTakingDamage(amount, whom, type);
	if (amount > this.ship.energy) return; // Ship is good as dead, don't waste time (especially if it collided with a station or got Q-bombed!)
	
	while (amount > 0.0)
	{
		var internal_damage = (Math.random() & 31) < amount; // not really sure what this does but...
		
		if (internal_damage)
		{
			worldScripts.NPC_Equipment_Damage._NPC_takeInternalDamage(this.ship)
		}
		amount -= 32;
	}
}
this._NPC_takeInternalDamage = function(ship)
{
	// should all types do this?
	
	var n_cargo = ship.cargoSpaceCapacity;
	var n_mass = ship.mass / 10000;
	var n_considered = Math.floor((n_cargo + n_mass) * ship.script.EqDmg_serviceLevel / 100); // real thing uses ship trade-in factor but NPCs don't have this
	var damage_to = n_considered == 0 ? 0 : Math.floor(Math.random() * n_considered);
	
	var cargopods = [];
	for (item in  ship.cargoList) // need to construct list of individual pods
	{
		for (var i=0; i < ship.cargoList[item].quantity; i++)
		{
			cargopods.push(ship.cargoList[item].commodity)
		} 
	}
	if (damage_to < cargopods)
	{
		ship.adjustCargo(cargopods[damage_to], -1);
		log("NPC_Equipment_Damage", "Destroyed 1 unit of"+cargopods[damage_to]+" on "+ship.displayName)
	}
	else
	{
		damage_to = n_considered - (damage_to + 1); // reverse the die roll
		var damageableCounter = 0;
		var damageableOdds = 0.0;
		var damageableEquip = [];
		for (i in ship.equipment)
		{
			var eq = ship.equipment[i]
			if (eq.canBeDamaged && ship.equipmentStatus(eq.equipmentKey) == "EQUIPMENT_OK")
			{
				damageableCounter++;
				damageableOdds += eq.damageProbability;
				damageableEquip.push(eq); // list only equipment which can be damaged & isn't already
			}
		}
		
		if (damage_to < damageableCounter)
		{
			var target = Math.random() * damageableOdds;
			var accumulator = 0.0;
			for (i in ship.equipment)
			{
				// var eq = ship.equipment[i] // no need to call infoForKey, the info object is what's listed?
				var eq = damageableEquip[i];
				
				accumulator += eq.damageProbability;
				if (accumulator > target)
				{
					// check damageable, damage, apply handlers, return
					if (!eq.canBeDamaged) return;
					
					ship.setEquipmentStatus(eq.equipmentKey, "EQUIPMENT_DAMAGED");
					
					log("NPC_Equipment_Damage", "damaging "+eq.equipmentKey+" on "+ship.displayName)
					
					var handlers = worldScripts.NPC_Equipment_Damage.NPC_equipmentDamagedHandlers
					for (h in handlers)
					{
						handlers[h].apply(ship.script, [eq.equipmentKey]);
					}
					return;
				}
			}
		}
	}
}
this._shipconf_equipmentDamaged = function(equipmentKey)
{
	if (this.$equipmentDamaged_Event)
	{
		this.$equipmentDamaged_Event(equipmentKey)
		return;
	}
	log ("NPC Equipment Damage", "Using old Ship Configuration equip dmg code for equipment "+equipmentKey)
	var conf = worldScripts.ShipConfiguration_Core;
	if (conf._engines.indexOf(equipmentKey) >= 0)
	{
		// damage the injectors before the engine
		if (this.ship.equipmentStatus(conf.$equipmentItemInUse("fuelinjectors", this.ship)) == "EQUIPMENT_OK")
		{
			this.ship.setEquipmentStatus(equipmentKey, "EQUIPMENT_OK");
			this.ship.setEquipmentStatus(conf.$equipmentItemInUse("fuelinjectors", this.ship), "EQUIPMENT_DAMAGED");
			this.ship.setEquipmentStatus("EQ_FUEL_INJECTION", "EQUIPMENT_DAMAGED")
			return;
		}
	}
	if (conf._energy.indexOf(equipmentKey) >= 0)
	{
		if (this.ship.equipmentStatus("EQ_NPC_NAVAL_ENERGY_UNIT") == "EQUIPMENT_OK")
		{
			this.ship.setEquipmentStatus(equipmentKey, "EQUIPMENT_OK")
			this.ship.setEquipmentStatus("EQ_NPC_NAVAL_ENERGY_UNIT", "EQUIPMENT_DAMAGED")
			worldScripts.NPC_Energy_Units.NPC_energy_equipmentDamaged("EQ_NPC_NAVAL_ENERGY_UNIT")
			return;
		}
		if (this.ship.equipmentStatus("EQ_NPC_ENERGY_UNIT") == "EQUIPMENT_OK")
		{
			this.ship.setEquipmentStatus(equipmentKey, "EQUIPMENT_OK")
			this.ship.setEquipmentStatus("EQ_NPC_ENERGY_UNIT", "EQUIPMENT_DAMAGED")
			worldScripts.NPC_Energy_Units.NPC_energy_equipmentDamaged("EQ_NPC_ENERGY_UNIT")
			return;
		}
		this.ship.energyRechargeRate = 0;
		if (!this._energyTimer) this._energyTimer = new Timer(this, worldScripts.NPC_Equipment_Damage._drainEnergy.bind(this), 1, 1);
	}
	if (conf._fuelinjectors.indexOf(equipmentKey) >= 0)
	{
		this.ship.setEquipmentStatus("EQ_FUEL_INJECTION", "EQUIPMENT_DAMAGED")
	}
}
this._drainEnergy = function()
{
	this.ship.energy -= 1;
	if (this.ship.energy < 30)
	{
		this._energyTimer.stop()
		delete this._energyTimer;
		this.ship.energyRechargeRate = 0;
	}
}
 |