Caduceus Autorepair update for OSE

For test results, bug reports, announcements of new builds etc.

Moderators: winston, another_commander, Getafix

pmw57
---- E L I T E ----
---- E L I T E ----
Posts: 389
Joined: Sat Sep 26, 2009 2:14 pm
Location: Christchurch, New Zealand

Caduceus Autorepair update for OSE

Post by pmw57 »

The caduceus autorepair script is updated to protect the timers from causing potential damage.
CaduceusAutorepair.js

The code has been updated so that it is easier to consistently maintain, and is formatted in a more stable manner. As there are multiple timer events occurring, some timer management method have been added to the script.

Code: Select all

this.timerSettings = {
	'damageControlTimer': {func: this.repairShip, delay: 60, interval: 300}
};
this.startTimer = function (timerName) {
	var timerSettings;
	if (this[timerName]) {
		this[timerName].start();
		return this[timerName];
	} else if (this.timerSettings[timerName]) {
		timerSettings = this.timerSettings[timerName];
		log(timerSettings.func);
		return new Timer(this, timerSettings.func, timerSettings.delay, timerSettings.interval);
	}
	return null;
};
this.stopTimer = function (timerName) {
	if (this[timerName]) {
		this[timerName].stop();
		delete this[timerName];
	}
};
The following is the updated code for timer cleanup:

Code: Select all

this.shipDockedWithStation = function () {
	this.stopTimer('damageNodeTimer');
};

this.playerWillEnterWitchspace = this.shipDied = function () {
	this.stopTimer('damageControlTimer');
	this.stopTimer('damageNodeTimer');
};
Last edited by pmw57 on Thu Oct 15, 2009 9:46 am, edited 3 times in total.
A trumble a day keeps the doctor away, and the tax man;
even the Grim Reaper keeps his distance.
-- Paul Wilkins
pmw57
---- E L I T E ----
---- E L I T E ----
Posts: 389
Joined: Sat Sep 26, 2009 2:14 pm
Location: Christchurch, New Zealand

Post by pmw57 »

There are some code issues with the caduceus autorepair script.

There is no let keyword in javascript. Instead, var must be used instead. These declarations have been moved to the top of the method.

The array loops have been updated so that a more standard technique can be applied. Instead of looping until the index is <= (array length - 1) a better form of loop is until the index is < (array length)

this.screenListLength is also set, but as it's not used anywhere so it has been taken out.

Switch statements - the case sections are not code blocks, and should not be surrounded with braces. It's also best to end the switch statements with a default section.
A trumble a day keeps the doctor away, and the tax man;
even the Grim Reaper keeps his distance.
-- Paul Wilkins
pmw57
---- E L I T E ----
---- E L I T E ----
Posts: 389
Joined: Sat Sep 26, 2009 2:14 pm
Location: Christchurch, New Zealand

Post by pmw57 »

From the original code, this doesn't do what's written on the tin.

Code: Select all

		this.fixChance = this.eqChance[this.damagedItemNumber]; // for tech <9 chance = 100%, dropping 10% per level above 8.
		this.fixTry = Math.random() * 100;
		if (this.fixTry < this.fixChance) {
			this.fixItem();
		} else {
			player.consoleMessage(this.fixedName + " is still offlined, Captain. We shall try again soon.", 5);
		}
this.eqChance contains 70% values, and that's it.

Was there a reason that the tech-level chance wasn't implemented, or is the comment a remainder from when it was tried out and found to be less than useful?

Is the comment to be implemented or removed, is what I'm getting at.
A trumble a day keeps the doctor away, and the tax man;
even the Grim Reaper keeps his distance.
-- Paul Wilkins
pmw57
---- E L I T E ----
---- E L I T E ----
Posts: 389
Joined: Sat Sep 26, 2009 2:14 pm
Location: Christchurch, New Zealand

Post by pmw57 »

Another update that will occur to this script is to improve the list of items that can be repaired. They need to be handled in a better way than a series of named arrays, because things easily become missing, or out of place.

Case in point, the third array lists a percentage of chance for the previous arrays, but the percentage list has a few less items in it than the other arrays. When list items from near the end are chosen, they won't have a valid percentage associated with them and the script goes boom.

The existing code is:

Code: Select all

	damagedList = ["EQ_WORMHOLE_SCANNER_DAMAGED", "EQ_MISJUMP_ANALYSER_DAMAGED", "EQ_MILITARY_SCANNER_FILTER_DAMAGED", ...];
	this.screenList = ["Wormhole Scanner", "Misjump Analyser", "Military Scanner Filtering", ...];
	this.eqChance = [70, 70, 70, ...];
The way to improve this to prevent further issues is to connect the individual items together as one entity.

Code: Select all

	damagedList = [
		{name: "EQ_WORMHOLE_SCANNER_DAMAGED", desc: "Wormhole Scanner", chance: 70},
		{name: "EQ_MISJUMP_ANALYSER_DAMAGED", desc: "Misjump Analyser", chance: 70},
		{name: "EQ_MILITARY_SCANNER_FILTER_DAMAGED", desc: "Military Scanner Filtering", chance: 70},
		...
	];
The rest of the related code is updated as well. Instead of adding vast numbers of temporary variables to the ship, the code instead uses local variables that are safely thrown away when the method finishes.

To finish this part of things off, chopping off a part of a string has been improved too.

Before:

Code: Select all

"SOME_ITEM_DAMAGED".substring(0,this.damagedItem.length-8);
After:

Code: Select all

"SOME_ITEM_DAMAGED".slice(0, -8);
Last edited by pmw57 on Thu Oct 15, 2009 9:41 am, edited 1 time in total.
A trumble a day keeps the doctor away, and the tax man;
even the Grim Reaper keeps his distance.
-- Paul Wilkins
User avatar
ClymAngus
---- E L I T E ----
---- E L I T E ----
Posts: 2514
Joined: Tue Jul 08, 2008 12:31 am
Location: London England
Contact:

Post by ClymAngus »

excellent work I shall update tonight and add you in on the read me credits. :)
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5528
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

The array mis-match is because this code is borrowed from another OXP (Repair Bots), and got partly updated on the way to include additional new items that aren't in RB (they're new in later versions of trunk). Unfortunately the update wasn't done fully, as only one of the required arrays got done, not the parallel one (the 3rd one with the chances).

Originally this wasn't a ship-script, but a worldScript, so again the variable usage part has suffered a bit from the change of application.

Learned something new with the slice command though, although the improvement looks quite minimal ;)

It may help a little bit if you look at repair bots OXP (available via my sig) so you can see the "original" form and application of this script, which was borrowed for use as a Caddy self-repair one (without my knowledge, but that's no issue for me as anyone is welcome to borrow such code).
pmw57
---- E L I T E ----
---- E L I T E ----
Posts: 389
Joined: Sat Sep 26, 2009 2:14 pm
Location: Christchurch, New Zealand

Post by pmw57 »

Thargoid wrote:
Learned something new with the slice command though, although the improvement looks quite minimal ;)
In terms of execution of code it is minimal, however when it comes to other people understanding the of code it adds a lot there.

Sometimes improvements are about making things more understandable for other people, but caution is the watch-word of the wise, as what is understandable for one may not be understandable for others.

Here endeth the lesson :twisted:

But really, your comment is welcome., so thanks :)
There isn't all that much to improve when it comes to your code, which is a wonderful sight to see.
A trumble a day keeps the doctor away, and the tax man;
even the Grim Reaper keeps his distance.
-- Paul Wilkins
pmw57
---- E L I T E ----
---- E L I T E ----
Posts: 389
Joined: Sat Sep 26, 2009 2:14 pm
Location: Christchurch, New Zealand

Post by pmw57 »

To remove confusion, the false comments about the repair chance being based on the tech level have been removed from this script.

The CaduceusAutorepair.js file on box.net has been updated, as well as has ose npc timer scripts.7z
A trumble a day keeps the doctor away, and the tax man;
even the Grim Reaper keeps his distance.
-- Paul Wilkins
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5528
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

Why is it a false comment? We have:

Code: Select all

if (this.fixTry < this.fixChance) { 
         this.fixItem(); }
Hence the chance to achieve the repair (via this.fixItem() function) depends on this.fixTry (a random number) being less than this.fixChance (which is set from this.eqChance for the given item), giving the tech level dependence for higher tech items as per the comment?

Or are you referring to a different comment?
pmw57
---- E L I T E ----
---- E L I T E ----
Posts: 389
Joined: Sat Sep 26, 2009 2:14 pm
Location: Christchurch, New Zealand

Post by pmw57 »

Thargoid wrote:
Or are you referring to a different comment?
Yes. This is the comment in question.

Code: Select all

// percentage chance of equipment being fixed, for tech <9 chance = 100%, dropping 10% per level above 8.
Nothing in the code relates to the tech level. Instead, all repairs have a 70% chance of being repaired at any one time. That is the reason for removing the misleading comment.

The comment could have been put there earlier but been given up on, or it could have been placed there afterwards as an idea that didn't come to fruition. Either way, the comment is misleading and should not be there.

It would be easy enough to implement what the comment says, but that depends on if it's a viable idea or not.
A trumble a day keeps the doctor away, and the tax man;
even the Grim Reaper keeps his distance.
-- Paul Wilkins
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5528
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

this.eqChance should be set per-item via the third array (the one that wasn't added to when the new items were put in), and that should give the dependence. It's the tech level of the equipment, which at the time the code was originally written couldn't be got directly (it can now I think).

If that is no longer the case in the new utilisation of the code then fair enough. I should point out the original code (repair bots OXP) is mine, and there it did exactly as it says on the tin...
pmw57
---- E L I T E ----
---- E L I T E ----
Posts: 389
Joined: Sat Sep 26, 2009 2:14 pm
Location: Christchurch, New Zealand

Post by pmw57 »

Thargoid wrote:
this.eqChance should be set per-item via the third array (the one that wasn't added to when the new items were put in), and that should give the dependence. It's the tech level of the equipment, which at the time the code was originally written couldn't be got directly (it can now I think).
Yep, the individual item chance is used to determine the likelyhood of repair, all historically (and currently) set to 70%.
Thargoid wrote:
If that is no longer the case in the new utilisation of the code then fair enough. I should point out the original code is mine, and there it did exactly as it says on the tin...
That's great to know, and is a fine example of how comments do not survive change very well. Comments that explain why, instead of how, tend to have better survival rates. :D
A trumble a day keeps the doctor away, and the tax man;
even the Grim Reaper keeps his distance.
-- Paul Wilkins
User avatar
Cmdr Wyvern
---- E L I T E ----
---- E L I T E ----
Posts: 1649
Joined: Tue Apr 11, 2006 1:47 am
Location: Somewhere in the great starry void

Post by Cmdr Wyvern »

This is the script that's currently in the neocaduceus download.

Code: Select all

this.name = "Caduceus Damage Control Node";
this.author = "Modified Thargoid's repair bots for Caduceus, by Wyvern";
this.copyright = "2009";
this.description = "Nanite autorepair node for Caduceus class bioships. Simulates an AI controlled self-healing nanoforge and damage control teams to repair kit over time.";
this.version = "0.3";

this.shipLaunchedFromStation = function() {
   if (player.ship.hasEquipment("EQ_DCN")) {   
      if (this.damageControlTimer) {
         this.damageControlTimer.start();
      } else {
         this.damageControlTimer = new Timer(this, this.repairShip, 60, 300);
      }
   }
};

this.shipExitedWitchspace = function() {
   if (player.ship.hasEquipment("EQ_DCN")) {   
      if (this.damageControlTimer) {
         this.damageControlTimer.start();
      } else {
         this.damageControlTimer = new Timer(this, this.repairShip, 60, 300);
      }
   }
};

this.equipmentDamaged = this.equipmentDestroyed  = function(equipment) {
   if (equipment == "EQ_DCN") {
      if(this.damageControlTimer) {
         this.damageControlTimer.stop();
         delete this.damageControlTimer;
      }
      if(this.damageNodeTimer) {
         this.damageNodeTimer.start();
      } else {
         this.damageNodeTimer = new Timer(this, this.restoreNode, 0, 60);
      }
   }
};
   
this.playerWillEnterWitchspace = function() {
    if (this.damageControlTimer) {
      this.damageControlTimer.stop();
      delete this.damageControlTimer;
   }
    if (this.damageNodeTimer) {
      this.damageNodeTimer.stop();
      delete this.damageNodeTimer;
   }
};

this.shipDockedWithStation = function()
{
   if(this.damageControlTimer) {   
      this.damageControlTimer.stop();
      delete this.damageControlTimer;
   }           
}

this.shipDied = function()
{
   if(this.damageControlTimer) {   
      this.damageControlTimer.stop();
      delete this.damageControlTimer;
   }
   if(this.damageNodeTimer) {   
      this.damageNodeTimer.stop();
      delete this.damageNodeTimer;
   }                 
}

this.repairShip = function()
   {
   if (0 < oolite.compareVersion("1.72"))
      {
      // 1.71.x or earlier
      this.thePlayerShip = player;
      }
   else
      {
      // 1.72 or later
      this.thePlayerShip = player.ship;
      }
   this.damagedList = ["EQ_UPS_IDCLEANER_DAMAGED", "EQ_UPS_UNIVERSAL_SCANNER_DAMAGED", "EQ_UPS_POLICE_SCANNER_DAMAGED", "EQ_ECM_DAMAGED", "EQ_FUEL_SCOOPS_DAMAGED", "EQ_ESCAPE_POD_DAMAGED", "EQ_ENERGY_BOMB_DAMAGED", "EQ_ENERGY_UNIT_DAMAGED", "EQ_NAVAL_ENERGY_UNIT_DAMAGED", "EQ_GAL_DRIVE_DAMAGED", "EQ_CLOAKING_DEVICE_DAMAGED", "EQ_FUEL_INJECTION_DAMAGED", "EQ_SCANNER_SHOW_MISSILE_TARGET_DAMAGED", "EQ_MULTI_TARGET_DAMAGED", "EQ_ADVANCED_COMPASS_DAMAGED", "EQ_ADVANCED_NAVIGATIONAL_ARRAY_DAMAGED", "EQ_TARGET_MEMORY_DAMAGED", "EQ_SHIELD_BOOSTER_DAMAGED", "EQ_NAVAL_SHIELD_BOOSTER_DAMAGED", "EQ_FRAME_FUEL_COLLECTOR_DAMAGED", "EQ_FRAME_BOUNTY_SCANNER_DAMAGED", "EQ_EEU_DAMAGED", "EQ_MISSILE_ANALYSER_DAMAGED", "EQ_AMS_DAMAGED", "EQ_DUMMY" ];
   this.screenList = ["Pirate ID Cleaner", "Universal Scanner", "GalCop Scanner", "E.C.M.", "Fuel Scoops", "Escape Pod", "Energy Bomb", "Extra Energy Enit", "Naval Energy Unit", "Galactic Hyperdrive", "Cloaking Device", "Witchdrive Fuel Injectors", "Scanner Targeting Enhancement", "Multi-Targeting System", "Advanced Space Compass", "Advanced Navigational Array", "Target System Memory Expansion", "Shield Boosters", "Naval Shield Enhancement", "Fuel Collector", "Bounty Scanner", "Emergency Energy Unit", "Missile Analyser", "Anti-Missile System", "Nothing could be" ];
   this.eqChance = [60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 100]; // percentage chance of equipment being fixed, for tech <9 chance = 100%, dropping 10% per level above 8.
   this.damListLength = this.damagedList.length - 1;
   this.screenListLength = this.screenList.length - 1;
   this.playerDamagedList = []; // reset the list for each new usage of the repair bots.
   this.playerDamagedItem = []; // array of locations within the above list.
   let eqCounter = 0 ; // reset the counter
   for(eqCounter = 0;eqCounter<=this.damListLength;eqCounter++)
      {
      this.checkItem = this.damagedList[eqCounter];
      if(this.thePlayerShip.hasEquipment(this.checkItem))
         {
         this.playerDamagedList.push(this.checkItem) // if it's broke, add it to the list.
         this.playerDamagedItem.push(eqCounter) // keep a note of where in the list it is.
         }
      }
   this.plistlength = this.playerDamagedList.length;
   if(this.plistlength == 0)
      {
      player.consoleMessage("All systems nominal.",5)
      }
   else
      {
      let damagedEquipment = Math.floor(Math.random() * this.plistlength); // pick a random element from the list...
      this.damagedItem = this.playerDamagedList[damagedEquipment]; // ...define the item...
      this.damagedItemNumber = this.playerDamagedItem[damagedEquipment]; // where the item to be repaired is in the list
      this.fixedItem = this.damagedItem.substring(0,this.damagedItem.length-8);
      this.fixedName = this.screenList[this.damagedItemNumber]; // define it's screen name
      this.fixChance = this.eqChance[this.damagedItemNumber]; // for tech <9 chance = 100%, dropping 10% per level above 8.
      this.fixTry = Math.random() * 100;
      if(this.fixTry < this.fixChance)
         {
         this.fixItem();
         }
      else
         {
         player.consoleMessage(this.fixedName + " is still offlined, Captain. We shall try again soon.",5);
         }
      }
   }

this.restoreNode = function()
   {
   if (0 < oolite.compareVersion("1.72"))
      {
      // 1.71.x or earlier
      this.thePlayerShip = player;
      }
   else
      {
      // 1.72 or later
      this.thePlayerShip = player.ship;
      }
   this.damagedList = ["EQ_DCN_DAMAGED", "EQ_DUMMY" ];
   this.screenList = ["Damage Control Node", "Nothing could be" ];
   this.eqChance = [75, 100]; // percentage chance of equipment being fixed, for tech <9 chance = 100%, dropping 10% per level above 8.
   this.damListLength = this.damagedList.length - 1;
   this.screenListLength = this.screenList.length - 1;
   this.playerDamagedList = []; // reset the list for each new usage of the repair bots.
   this.playerDamagedItem = []; // array of locations within the above list.
   let eqCounter = 0 ; // reset the counter
   for(eqCounter = 0;eqCounter<=this.damListLength;eqCounter++)
      {
      this.checkItem = this.damagedList[eqCounter];
      if(this.thePlayerShip.hasEquipment(this.checkItem))
         {
         this.playerDamagedList.push(this.checkItem) // if it's broke, add it to the list.
         this.playerDamagedItem.push(eqCounter) // keep a note of where in the list it is.
         }
      }
   this.plistlength = this.playerDamagedList.length;
   if(this.plistlength == 0) {
      player.consoleMessage("Damage Control Node regenerated! Repairs resuming.",5)
      if(this.damageNodeTimer) {
         this.damageNodeTimer.stop();
         delete this.damageNodeTimer;
      }
      if(this.damageControlTimer) {
         this.damageControlTimer.start();
      } else {
         this.damageControlTimer = new Timer(this, this.repairNode, 60, 300)
      }
   } else {
      let damagedEquipment = Math.floor(Math.random() * this.plistlength); // pick a random element from the list...
      this.damagedItem = this.playerDamagedList[damagedEquipment]; // ...define the item...
      this.damagedItemNumber = this.playerDamagedItem[damagedEquipment]; // where the item to be repaired is in the list
      this.fixedItem = this.damagedItem.substring(0,this.damagedItem.length-8);
      this.fixedName = this.screenList[this.damagedItemNumber]; // define it's screen name
      this.fixChance = this.eqChance[this.damagedItemNumber]; // for tech <9 chance = 100%, dropping 10% per level above 8.
      this.fixTry = Math.random() * 100;
      if(this.fixTry < this.fixChance)
         {
         this.fixItem();
         }
      else
         {
         player.consoleMessage(this.fixedName + " is regenerating. Stand by.",5);
         }
      }
   }

this.fixItem = function()
   {
   this.thePlayerShip.setEquipmentStatus(this.fixedItem,"EQUIPMENT_OK"); // and actually fix the thing!
   player.consoleMessage(this.fixedName + " repaired and online.", 5)
   switch(this.fixedItem) // specific OXP equipment which need rebooting after fixing, or have other issues.
      {
      case "EQ_FRAME_FUEL_COLLECTOR":
         {
         if(worldScripts["Fuel Collector"])
            {
            worldScripts["Fuel Collector"].shipLaunchedFromStation(); // restart the timers in it's world script
            }
         }
         break;
      case "EQ_FRAME_BOUNTY_SCANNER":         
         {
         if(worldScripts["Bounty Scanner"])
            {
            worldScripts["Bounty Scanner"].shipLaunchedFromStation(); // restart the timers in it's world script
            }
         }
         break;
      case "EQ_EEU":
         {
         if(worldScripts["Emergency Energy Unit"])
            {
            worldScripts["Emergency Energy Unit"].shipLaunchedFromStation(); // restart the timers in it's world script
            }
         }
         break;
      }
   } 
You'll notice a few things here.
- Chances reduced to 60%
- Non combat-essential and non-irreplaceable items removed.
- And, no bloody MASC. MASC is officially not supported, not by the devs or by me, and shouldn't be in the hands of the player IMHO. I'll bet the devs are wishing the bloody thing was never coded. Is Kaks twitching again? No, there won't ever be any support for it.
Running Oolite buttery smooth & rock stable w/ tons of eyecandy oxps on:
ASUS Prime X370-A
Ryzen 5 1500X
16GB DDR4 3200MHZ
128GB NVMe M.2 SSD (Boot drive)
1TB Hybrid HDD (For software and games)
EVGA GTX-1070 SC
1080P Samsung large screen monitor
User avatar
ClymAngus
---- E L I T E ----
---- E L I T E ----
Posts: 2514
Joined: Tue Jul 08, 2008 12:31 am
Location: London England
Contact:

Post by ClymAngus »

so artistic and hosting upshot is..........

until you code monkeys agree, I guess I'm leaving it as is.

Actually that's not strictly true. I go with the Wyvern. Why? Well wrote a novellette and built a ship (and prettying another one) with the dude. That's got to count for something on the "trust" stakes.
another_commander
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 6683
Joined: Wed Feb 28, 2007 7:54 am

Post by another_commander »

Cmdr Wyvern wrote:
- And, no bloody MASC. MASC is officially not supported, not by the devs or by me, and shouldn't be in the hands of the player IMHO. I'll bet the devs are wishing the bloody thing was never coded. [/b]
Actually, we have wished (and might as well make it so at some point) that the MASC and related Jammer be taken out of future releases. If a feature is not supported, leaving it in is just causing confusion, false bug reports and even unpredictable game behaviour. Until someone goes through the related code and corrects whatever monsters lay there, it's best if that code stays out of production builds.
Post Reply