Back to Index Page generated: Nov 12, 2024, 11:02:04 PM

Expansion NPC Equipment Damage

Content

Warnings

  1. Unknown key 'upload_date' at https://wiki.alioth.net/img_auth.php/2/21/Oolite.oxp.Ngalo.NPC_Equipment_Damage_0.3.0.oxz!manifest.plist

Manifest

from Expansion Manager's OXP list from Expansion Manifest
Description Randomly damages NPC equipment, imitating what Oolite does for player-ship internal damage as far as possible. Randomly damages NPC equipment, imitating what Oolite does for player-ship internal damage as far as possible.
Identifier oolite.oxp.Ngalo.NPC_Equipment_Damage oolite.oxp.Ngalo.NPC_Equipment_Damage
Title NPC Equipment Damage NPC Equipment Damage
Category Mechanics Mechanics
Author Ngalo, phkb, tsoj Ngalo, phkb, tsoj
Version 0.3.0 0.3.0
Tags Equal Rights for NPCs, fairness, equipment, damage Equal Rights for NPCs, fairness, equipment, damage
Required Oolite Version
Maximum Oolite Version
Required Expansions
Optional Expansions
  • oolite.oxp.Ngalo.N-Shields:0.6
  • oolite.oxp.phkb.ShipConfiguration:0.2.0
  • oolite.oxp.Ngalo.N-Shields:0.6
  • oolite.oxp.phkb.ShipConfiguration:0.2.0
  • Conflict Expansions
    Information URL http://wiki.alioth.net/index.php/NPC_equipment_damage_OXP n/a
    Download URL https://wiki.alioth.net/img_auth.php/2/21/Oolite.oxp.Ngalo.NPC_Equipment_Damage_0.3.0.oxz TODO
    License CC-BY-NC-SA CC-BY-NC-SA
    File Size n/a
    Upload date 1639155117

    Documentation

    Also read http://wiki.alioth.net/index.php/NPC%20Equipment%20Damage

    readme.txt

    NPC Equipment Damage 0.3.0
    by Ngalo
    
    Does what it says on the tin: allows NPC equipment to get damaged in combat, as much like the core player damage handling as I can manage.
    Also damages NPC cargo, because Oolite does both with the same code for the player.
    
    OXP equipment which needs to be disabled by script when damaged can push a handler onto the worldScripts.NPC_Equipment_Damage.NPC_equipmentDamagedHandlers array.
    Note that such handlers will be called as if they were in the damaged ship's script, not your worldScript.
    A simple example handler from my NPC Energy Units OXP:
    
    this.NPC_energy_equipmentDamaged = function(equipment)
    {
    	if (equipment == "EQ_NPC_NAVAL_ENERGY_UNIT") this.ship.energyRechargeRate /= worldScripts.NPC_Energy_Units.NEU_multiplier;
    	if (equipment == "EQ_NPC_ENERGY_UNIT") this.ship.energyRechargeRate /= worldScripts.NPC_Energy_Units.EEU_multiplier;
    }
    
    Contributors
    - Ngalo: author
    - phkb: fixed manifest, fixed bugs
    - tsoj: fixed bugs
    
    License:
    You may use, adapt, distribute etc. this Oolite Expansion Pack as permitted by the Creative Commons Attribution-NonCommercial-ShareAlike License (CC-BY-NC-SA).
    
    Version history:
    0.3.0	fixed manifest, fixed wrong probability of damage, fixed issue with N-Shields
    0.2.1	Added a small fix which prevents time-wasting if the damaged ship is about to die anyway.
    0.2		Made use of compatibility improvements in Ship Configuration OXP.
    		Prevented the script from trying to damage equipment which is already damaged, or which can't be damaged at all.
    
    0.1.1	Fixed 'quantity is not defined' bug in cargo damage code
    0.1		Initial WIP release

    Equipment

    This expansion declares no equipment. This may be related to warnings.

    Ships

    This expansion declares no ships. This may be related to warnings.

    Models

    This expansion declares no models. This may be related to warnings.

    Scripts

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