1
/*jslint indent: 4, maxlen: 120, maxerr: 50, white: true, es5: true, undef: true, regexp: true, newcap: true */
2
/*jshint es5: true, undef: true, eqnull: true, noempty: true, eqeqeq: true, boss: true, loopfunc: true, laxbreak: true,
3
strict: true, curly: true */
4
/*global Timer, addFrameCallback, removeFrameCallback, isValidFrameCallback */
6
/* Jaguar Company Tracker
8
* Copyright © 2012 Richard Thomas Harrison (Tricky)
10
* This work is licensed under the Creative Commons
11
* Attribution-Noncommercial-Share Alike 3.0 Unported License.
13
* To view a copy of this license, visit
14
* http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter
15
* to Creative Commons, 171 Second Street, Suite 300, San Francisco,
16
* California, 94105, USA.
18
* Ship/Effect related functions for the patrol tracker.
24
/* Standard public variables for OXP scripts. */
25
this.name = "jaguar_company_tracker.js";
26
this.author = "Tricky";
27
this.copyright = "© 2012 Richard Thomas Harrison (Tricky)";
28
this.license = "CC BY-NC-SA 3.0";
29
this.description = "Ship script for the Jaguar Company Tracker.";
32
/* Private variable. */
35
/* Ship event callbacks. */
37
/* Initialise various variables on ship birth. Oolite v1.76.1 and older. */
38
this.shipSpawned = function () {
39
/* No longer needed after setting up. */
40
delete this.shipSpawned;
44
/* Use a frame callback to keep the position constant. */
45
this.$trackerFCBReference = addFrameCallback(this.$invisibleTrackerFCB.bind(this));
48
/* Initialise various variables on effect birth. Oolite v1.77 and newer. */
49
this.effectSpawned = function () {
50
/* No longer needed after setting up. */
51
delete this.shipSpawned;
55
/* Updated by the visual effect frame callback. */
56
p_tracker.material = 0;
57
/* Use a frame callback to keep the position constant. */
58
this.$trackerFCBReference = addFrameCallback(this.$trackerFCB.bind(this));
61
/* Patrol tracker was destroyed.
64
* whom - entity that caused the death.
65
* why - cause as a string.
67
* Not triggered for Oolite v1.77 and newer visual effects.
69
this.shipDied = function (whom, why) {
70
var mainScript = worldScripts["Jaguar Company"],
74
if (whom && whom.isValid) {
75
destroyedBy = "ship#" + whom.entityPersonality + " (" + whom.displayName + ")";
77
if (system.shipsWithPrimaryRole("jaguar_company_patrol").length > 0) {
78
/* Patrol still around. Re-spawn. */
79
mainScript.$tracker = mainScript.$jaguarCompanyBase.spawnOne("jaguar_company_tracker");
83
if (p_tracker.logging && p_tracker.logExtra) {
84
log(this.name, "shipDied::" +
85
"ship#" + tracker.entityPersonality + " (" + tracker.displayName + ")" +
86
" was destroyed by " + destroyedBy +
91
/* The patrol tracker has just become invalid or was removed. */
92
this.shipRemoved = this.effectRemoved = this.entityDestroyed = this.$removeTrackerRefs = function () {
93
/* Stop and remove the timer. */
94
if (this.$trackerTimerReference) {
95
if (this.$trackerTimerReference.isRunning) {
96
this.$trackerTimerReference.stop();
99
delete this.$trackerTimerReference;
102
/* Stop and remove the frame callback. */
103
if (this.$trackerFCBReference) {
104
if (isValidFrameCallback(this.$trackerFCBReference)) {
105
removeFrameCallback(this.$trackerFCBReference);
108
delete this.$trackerFCBReference;
112
/* Other global functions. */
114
/* Setup the private main variable + some public variables. */
115
this.$setUp = function () {
116
/* Initialise the p_tracker variable object.
117
* Encapsulates all private global data.
120
/* Local copies of the logging variables. */
121
logging : worldScripts["Jaguar Company"].$logging,
122
logExtra : worldScripts["Jaguar Company"].$logExtra,
123
/* Updated by the timer. */
124
closestPatrolShip : null
127
/* Track the patrol ships every 0.25 seconds. */
128
this.$trackerTimerReference = new Timer(this, this.$trackerTimer, 0.25, 0.25);
131
/* Tracker timer. Updates the closest patrol ship position. */
132
this.$trackerTimer = function () {
133
var tracker = this.ship || this.visualEffect,
136
if (!tracker || !tracker.isValid) {
137
/* Tracker no longer valid. */
138
this.$removeTrackerRefs();
140
if (p_tracker.logging && p_tracker.logExtra) {
141
log(this.name, "$trackerTimer::Tracker not valid");
147
/* Search for the patrol ships. */
148
patrolShips = system.shipsWithPrimaryRole("jaguar_company_patrol", player.ship);
150
if (!patrolShips.length) {
151
/* We are on our own. Deactivate the black box. */
152
worldScripts["Jaguar Company"].$deactivateJaguarCompanyBlackbox();
154
if (p_tracker.logging && p_tracker.logExtra) {
155
log(this.name, "$trackerTimer::Tracker removed - no patrol ships");
161
/* Update the closest patrol ship. */
162
p_tracker.closestPatrolShip = patrolShips[0];
165
/* Tracker frame callback.
167
* Used by Oolite v1.76.1 or older.
170
* delta - amount of game clock time past since the last frame.
172
this.$invisibleTrackerFCB = function (delta) {
173
var tracker = this.ship,
174
cps = p_tracker.closestPatrolShip,
177
if (!tracker || !tracker.isValid) {
178
/* Tracker can be invalid for 1 frame. */
179
this.$removeTrackerRefs();
184
if (delta === 0.0 || !cps || !cps.isValid) {
185
/* Do nothing if paused or the position of the closest patrol ship has not been setup. */
189
/* Distance above the closest patrol ship. */
190
distance = 5 + cps.collisionRadius;
191
/* Keep the tracker above the closest patrol ship. */
192
tracker.position = cps.position.add(cps.orientation.vectorUp().multiply(distance));
195
/* Tracker frame callback.
197
* Used for visual effects.
200
* delta - amount of game clock time past since the last frame.
202
this.$trackerFCB = function (delta) {
203
var tracker = this.visualEffect,
204
cps = p_tracker.closestPatrolShip,
211
if (!tracker || !tracker.isValid) {
212
/* Tracker can be invalid for 1 frame. */
213
this.$removeTrackerRefs();
218
if (delta === 0.0 || !cps || !cps.isValid) {
219
/* Do nothing if paused or the closest patrol ship has not been setup. */
223
/* Player ship object. */
225
/* Vector pointing towards the target. */
226
vector = cps.position.subtract(PS.position).direction();
228
if (vector.dot(PS.heading) >= 0) {
229
p_tracker.material = 0;
231
p_tracker.material = 1;
234
if (!p_tracker.material) {
235
/* Change the tracker colour to be green. */
236
tracker.setMaterials({
237
jaguar_company_tracker : {
238
diffuse_color : ["0", "0.667", "0", "1"],
239
diffuse_map : "jaguar_company_tracker_diffuse.png",
240
emission_color : ["0", "0.05", "0", "1"],
242
specular_color : ["0", "0.2", "0", "1"]
245
} else if (p_tracker.material) {
246
/* Change the tracker colour to be red. */
247
tracker.setMaterials({
248
jaguar_company_tracker : {
249
diffuse_color : ["0.667", "0", "0", "1"],
250
diffuse_map : "jaguar_company_tracker_diffuse.png",
251
emission_color : ["0.05", "0", "0", "1"],
253
specular_color : ["0.2", "0", "0", "1"]
258
/* Distance in front of the player. */
259
distance = 100 + PS.collisionRadius;
260
/* Keep the tracker in front of the player. */
261
tracker.position = PS.position.add(PS.heading.multiply(distance));
262
/* Angle to the target from current heading. */
263
angle = PS.heading.angleTo(vector);
264
/* Cross vector for rotate. */
265
cross = PS.heading.cross(vector).direction();
266
/* Rotate the tracker by the angle. */
267
tracker.orientation = PS.orientation.rotate(cross, -angle);