-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathExtras.nut
381 lines (333 loc) · 11.7 KB
/
Extras.nut
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
/* Extra functions v.6 [2014-02-26],
* part of Minchinweb's MetaLibrary v.7
* Copyright © 2011-14 by W. Minchin. For more info,
* please visit https://github.com/MinchinWeb/openttd-metalibrary
*
* Permission is granted to you to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell this software, and provide these
* rights to others, provided:
*
* + The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the software.
* + Attribution is provided in the normal place for recognition of 3rd party
* contributions.
* + You accept that this software is provided to you "as is", without warranty.
*/
// TO-DO: Break this into Math, Geometry, and Extras
/* These are 'random' functions that didn't seem to fit well elsewhere.
*
* Comparison functions will return the first value if the two are equal
*/
/** \brief Extra functions
* \version v.5 (2012-07-01)
* \author W. Minchin (%MinchinWeb)
* \since MetaLibrary v.1
*
* These are 'random' functions that didn't seem to fit well elsewhere.
* Many of them are math helper functions. Many others are helpful in dealing
* geometry.
*/
class _MinchinWeb_Extras_ {
_infinity = null; ///< pointer to \_MinchinWeb\_C\_::Infinity()
constructor() {
this._infinity = _MinchinWeb_C_.Infinity();
}
/** \publicsection
* \brief Get the location of a sign.
* \param text message to search for
* \return TileID of the first instance where the sign matches the given
* text.
* \return `null` if no matching sign can be found.
* \static
*/
function SignLocation(text);
/** \brief Find the tile halfway between two other tiles.
* \param TileA one 'end' tile
* \param TileB the other 'end' tile
* \return the `TileID` of the tile halfway between `TileA` and `TileB`
* \static
*/
function MidPoint(TileA, TileB);
/** \brief Get the perpendicular slope
* \param SlopeIn original slope
* \return slope perpendicular to `SlopeIn` (as a floating point number)
* \note Perpendicular slopes are inverses of each other.
* \see Slope()
* \see \_MinchinWeb\_C\_.Infinity()
* \static
*/
function Perpendicular(SlopeIn);
/** \brief Get the slope between two tiles.
* \param TileA first 'end' tile
* \param TileB tile at the other 'end'
* \return Slope between the two tiles (typically as a floating point
* number.
* \return If the slope is vertical, "Infinity (`Constants.Infinity()`)"
* is returned.
* \return If the slope is flat (i.e. 0), `1/Infinity` is returned.
* \see \_MinchinWeb\_C\_.Infinity()
* \static
*/
function Slope(TileA, TileB);
/** \brief Does `Value` fall between the bounds?
* \param Bound1 one limit
* \param Bound2 another limit
* \param Value the value being tested
* \return `True` is `Value` falls between the bounds, `False` otherwise.
* \note This is helpful in that there is no requirement that `Bound1` be
* larger than `Bound2` or vis-versa.
* \see WithinFloat()
* \static
*/
function Within(Bound1, Bound2, Value);
/** \brief Does `Value` fall between the bounds?
* \param Bound1 one limit
* \param Bound2 another limit
* \param Value the value being tested
* \return `True` is `Value` falls between the bounds, `False` otherwise.
* \note This is helpful in that there is no requirement that `Bound1` be
* larger than `Bound2` or vis-versa.
* \note This version explicitly converts all three parameters to
* floating point numbers before comparing them.
* \see Within()
* \static
*/
function WithinFloat(Bound1, Bound2, Value);
/** \brief Takes the absolute value of both numbers and then returns the
* smaller of the two.
* \return the magnitude of the value closer to zero (this will always
* be positive).
* \see MinAbsFloatKeepSign()
* \see MaxAbsFloat()
* \static
*/
function MinAbsFloat(Value1, Value2);
/** \brief Takes the absolute value of both numbers and then returns the
* larger of the two.
* \return the magnitude of the value farther to zero (this will always
* be positive).
* \see MinAbsFloat()
* \see MaxAbsFloatKeepSign()
* \static
*/
function MaxAbsFloat(Value1, Value2);
/** \brief Returns the absolute value of a given number.
* \return the absolute value of a given number (this will always
* be positive) (this will typically be a floating point number).
* \static
*/
function AbsFloat(Value);
/** \brief Returns the sign of a given number
* \return +1 if the Value >= 0, -1 Value < 0
* \static
*/
function Sign(Value);
/** \brief Returns the smaller of the two numbers
* \return The smaller of the two numbers, as a floating point number.
* \see MaxFloat()
* \static
*/
function MinFloat(Value1, Value2);
/** \brief Returns the larger of the two numbers
* \return The larger of the two numbers, as a floating point number.
* \see MinFloat()
* \static
*/
function MaxFloat(Value1, Value2);
/** \brief Takes the absolute value of both numbers and then returns the
* number with the lesser of the two, sign intact.
* \see MaxAbsFloatKeepSign()
* \see MinAbsFloat()
* \static
*/
function MinAbsFloatKeepSign(Value1, Value2);
/** \brief Takes the absolute value of both numbers and then returns the
* number with the greater of the two, sign intact.
* \see MinAbsFloatKeepSign()
* \see MaxAbsFloat()
* \static
*/
function MaxAbsFloatKeepSign(Value1, Value2);
/** \brief The tile that is neighbouring `StartTile` that is closest to
* `TowardsTile`
*
* Given a `StartTile` and a `TowardsTile`, will give the tile immediately
* next (Manhattan Distance == 1) to `StartTile` that is closest to
* `TowardsTile`.
* \return a neighbouring tile to `StartTile`
* \static
*/
function NextCardinalTile(StartTile, TowardsTile);
/** \brief Returns the revision number of the current build of OpenTTD
* \see See AILib.Common for more details on what is contained in the
* full returned version number.
* \note I determine this at the beginning of my AI's run so that when I
* get bug reports, I know what version of OpenTTD was being run.
* \note This might also be useful if you want to turn on or off certain
* features, depending on if they are in the user's version of OpenTTD.
* \static
*/
function GetOpenTTDRevision();
/** \brief Get the minimum distance between TileID and any of the tiles
* in TargetArray
* \note This is designed such that it can be run as a validator on an
* AIList of tiles
* \param TileID Tile we measure distance from
* \param TargetArray An array to tiles that we want to measure distance
* to. This can also be an AIList where the items are
* tiles.
* \return the minimum distance between TileID and any of the TargetArray
* \note Distances is measured using Manhattan Distance
* \note Distances to invalid tiles is reported as `-1`; therefore
* invalid tiles are always 'closer' that valid tiles.
* \todo Remove invalid tiles from the TargetArray
*/
function MinDistance(TileID, TargetArray);
};
// == Function definitions =================================================
function _MinchinWeb_Extras_::SignLocation(text) {
local sign_list = AISignList();
for (local i = sign_list.Begin(); !sign_list.IsEnd(); i = sign_list.Next()) {
if(AISign.GetName(i) == text)
{
return AISign.GetLocation(i);
}
}
return null;
}
function _MinchinWeb_Extras_::MidPoint(TileA, TileB) {
local X = (AIMap.GetTileX(TileA) + AIMap.GetTileX(TileB)) / 2 + 0.5;
local Y = (AIMap.GetTileY(TileA) + AIMap.GetTileY(TileB)) / 2 + 0.5;
// the 0.5 is to make rounding work
X = X.tointeger();
Y = Y.tointeger();
return AIMap.GetTileIndex(X, Y);
}
function _MinchinWeb_Extras_::Perpendicular(SlopeIn) {
if (SlopeIn == 0) {
return this._infinity;
} else {
SlopeIn = SlopeIn.tofloat();
return (-1 / SlopeIn);
}
}
function _MinchinWeb_Extras_::Slope(TileA, TileB) {
local dx = AIMap.GetTileX(TileB) - AIMap.GetTileX(TileA);
local dy = AIMap.GetTileY(TileB) - AIMap.GetTileY(TileA);
// Zero check
if (dx == 0) {
return _MinchinWeb_C_.Infinity() * _MinchinWeb_Extras_.Sign(dy);
} else if (dy == 0) {
return (1.0 / _MinchinWeb_C_.Infinity()) * _MinchinWeb_Extras_.Sign(dx);
} else {
dx = dx.tofloat();
dy = dy.tofloat();
return (dy / dx);
}
}
function _MinchinWeb_Extras_::Within(Bound1, Bound2, Value)
{
local UpperBound = max(Bound1, Bound2);
local LowerBound = min(Bound1, Bound2);
return ((Value <= UpperBound) && (Value >= LowerBound));
}
function _MinchinWeb_Extras_::WithinFloat(Bound1, Bound2, Value) {
local UpperBound = _MinchinWeb_Extras_.MaxFloat(Bound1, Bound2) + _MinchinWeb_C_.FloatOffset();
local LowerBound = _MinchinWeb_Extras_.MinFloat(Bound1, Bound2) - _MinchinWeb_C_.FloatOffset();
local Value = Value.tofloat();
// _MinchinWeb_Log_.Note(" Extras.WithinFloat: Val=" + Value + " B1=" + Bound1 + " B2=" + Bound2 + " : UB=" + UpperBound + " LB=" + LowerBound + " is " + (Value <= UpperBound) + " " + (Value >= LowerBound) + " : " + ((Value <= UpperBound) && (Value >= LowerBound)) + " : above " + (Value - UpperBound) + " below " + (LowerBound - Value) + " : " + _MinchinWeb_C_.FloatOffset() , 7);
return ((Value <= UpperBound) && (Value >= LowerBound));
}
function _MinchinWeb_Extras_::MinAbsFloat(Value1, Value2) {
if (Value1 < 0) { Value1 *= -1.0; }
if (Value2 < 0) { Value2 *= -1.0; }
if (Value1 <= Value2) {
return Value1;
} else {
return Value2;
}
}
function _MinchinWeb_Extras_::MaxAbsFloat(Value1, Value2) {
if (Value1 < 0) { Value1 *= -1.0; }
if (Value2 < 0) { Value2 *= -1.0; }
if (Value1 >= Value2) {
return Value1;
} else {
return Value2;
}
}
function _MinchinWeb_Extras_::AbsFloat(Value)
{
if (Value >= 0) {
return Value;
} else {
return (Value * (-1.0));
}
}
function _MinchinWeb_Extras_::Sign(Value) {
if (Value >= 0) {
return 1;
} else {
return -1;
}
}
function _MinchinWeb_Extras_::MinFloat(Value1, Value2) {
if (Value1 <= Value2) {
return (Value1).tofloat();
} else {
return (Value2).tofloat();
}
}
function _MinchinWeb_Extras_::MaxFloat(Value1, Value2) {
if (Value1 >= Value2) {
return (Value1).tofloat();
} else {
return (Value2).tofloat();
}
}
function _MinchinWeb_Extras_::MinAbsFloatKeepSign(Value1, Value2) {
local Sign1 = _MinchinWeb_Extras_.Sign(Value1);
local Sign2 = _MinchinWeb_Extras_.Sign(Value2);
if (Value1 < 0) { Value1 *= -1.0; }
if (Value2 < 0) { Value2 *= -1.0; }
if (Value1 <= Value2) {
return (Value1 * Sign1).tofloat();
} else {
return (Value2 * Sign2).tofloat();
}
}
function _MinchinWeb_Extras_::MaxAbsFloatKeepSign(Value1, Value2) {
local Sign1 = _MinchinWeb_Extras_.Sign(Value1);
local Sign2 = _MinchinWeb_Extras_.Sign(Value2);
if (Value1 < 0) { Value1 *= -1.0; }
if (Value2 < 0) { Value2 *= -1.0; }
if (Value1 >= Value2) {
return (Value1 * Sign1).tofloat();
} else {
return (Value2 * Sign2).tofloat();
}
}
function _MinchinWeb_Extras_::NextCardinalTile(StartTile, TowardsTile) {
local Tiles = AITileList();
local offsets = [AIMap.GetTileIndex(0, 1), AIMap.GetTileIndex(0, -1),
AIMap.GetTileIndex(1, 0), AIMap.GetTileIndex(-1, 0)];
foreach (offset in offsets) {
Tiles.AddItem(StartTile + offset, AIMap.DistanceSquare(StartTile + offset, TowardsTile));
}
Tiles.Sort(AIList.SORT_BY_VALUE, AIList.SORT_ASCENDING);
return Tiles.Begin();
}
function _MinchinWeb_Extras_::GetOpenTTDRevision() {
local Version = AIController.GetVersion();
local Revision = Version & 0x0007FFFF;
return Revision;
}
function _MinchinWeb_Extras_::MinDistance(TileID, TargetArray) {
local MinDist = _MinchinWeb_C_.Infinity();
foreach (Target in TargetArray) {
// note that with AIList's, Target is the `Value`, not the `Item`
MinDist = min(MinDist, AITile.GetDistanceManhattanToTile(TileID, Target));
}
return MinDist;
}
// EOF