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;
}
}
|