~ubuntu-branches/debian/stretch/assaultcube-data/stretch

« back to all changes in this revision

Viewing changes to source/src/bot/bot_util.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Gonéri Le Bouder, Ansgar Burchardt, Gonéri Le Bouder
  • Date: 2010-04-02 23:37:55 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100402233755-kf74fxwlu634o6vg
Tags: 1.0.4+repack1-1
[ Ansgar Burchardt ]
* debian/control: fix typo in short description

[ Gonéri Le Bouder ]
* Upgrade to 1.0.4
* bump standards-version to 3.8.4
* Add Depends: ${misc:Depends} just to avoid a lintian warning
* Add a debian/source/format file for the same reason

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// C++ Implementation: bot_util
 
3
//
 
4
// Description: Basic util functions, mostly bot related
 
5
//
 
6
//
 
7
// Author:  <rickhelmus@gmail.com>
 
8
//
 
9
// 
 
10
//
 
11
//
 
12
 
 
13
#include "pch.h"
 
14
#include "bot.h"
 
15
 
 
16
// Function code by PMB - Begin
 
17
 
 
18
 
 
19
// Random functions begin
 
20
// copied from
 
21
// http://forums.bots-united.com/showthread.php?t=244&page=1&pp=10&highlight=random
 
22
// So credits to PMB and the person(s) who actually made it :]
 
23
 
 
24
// maximum value returned by our number generator (2^31 - 1 = 0x7FFFFFFF)
 
25
#define LRAND_MAX 2147483647L
 
26
long lseed; // our random number generator's seed
 
27
 
 
28
long lrand (void)
 
29
{
 
30
     // this function is the equivalent of the rand() standard C library function,
 
31
     // except that whereas rand() works only with short integers
 
32
     // (i.e. not above 32767), this function is able to generate 32-bit random
 
33
     // numbers. Isn't that nice ?
 
34
     // credits go to Ray Gardner for his fast implementation of minimal random
 
35
     // number generators
 
36
     // http://c.snippets.org/snip_lister.php?fname=rg_rand.c
 
37
     
 
38
     // compose the two 16-bit parts of the long integer and assemble them
 
39
     static unsigned long lrand_lo, lrand_hi;
 
40
     lrand_lo = 16807 * (long) (lseed & 0xFFFF); // low part
 
41
     lrand_hi = 16807 * (long) ((unsigned long) lseed >> 16);
 
42
     // high part
 
43
     lrand_lo += (lrand_hi & 0x7FFF) << 16;
 
44
     // assemble both in lrand_lo
 
45
     // is the resulting number greater than LRAND_MAX (half the capacity) ?
 
46
     if (lrand_lo > LRAND_MAX)
 
47
     {
 
48
          lrand_lo &= LRAND_MAX; // then get rid of the disturbing bit
 
49
          lrand_lo++; // and increase it a bit (to avoid overflow problems, I suppose)
 
50
     }
 
51
     
 
52
     lrand_lo += lrand_hi >> 15;
 
53
     // now do twisted maths to generate the next seed
 
54
     // is the resulting number greater than LRAND_MAX (half the capacity) ?
 
55
     if (lrand_lo > LRAND_MAX)
 
56
     {
 
57
          lrand_lo &= LRAND_MAX; // then get rid of the disturbing bit
 
58
          lrand_lo++; // and increase it a bit (to avoid overflow problems, I suppose)
 
59
     }
 
60
     // now we've got our (pseudo-)random number.
 
61
     lseed = (long) lrand_lo; // put it in the seed for next time
 
62
     return (lseed); // and return it. Yeah, simple as that.
 
63
}
 
64
 
 
65
void lsrand (unsigned long initial_seed)
 
66
{
 
67
     // this function initializes the random seed based on the initial seed value
 
68
     // passed in the initial_seed parameter. Since random seeds are
 
69
     // usually initialized with the time of day, and time is a value that
 
70
     // changes slowly, we bump the seed twice to have it in a more
 
71
     // random state for future calls of the random number generator.
 
72
     
 
73
     // fill in the initial seed of the random number generator
 
74
     lseed = (long) initial_seed; 
 
75
     lseed = lrand (); // bump it once
 
76
     lseed = lrand (); // bump it twice
 
77
     return; // that's all folks
 
78
}
 
79
 
 
80
long RandomLong (long from, long to)
 
81
{
 
82
     // this function returns a random integer number between (and including)
 
83
     // the starting and ending values passed by parameters from and to.
 
84
     if (to <= from) 
 
85
          return (from);
 
86
          
 
87
     return (from + lrand () / (LRAND_MAX / (to - from + 1)));
 
88
}
 
89
 
 
90
float RandomFloat (float from, float to)
 
91
{
 
92
     // this function returns a random floating-point number between (and including)
 
93
     // the starting and ending values passed by parameters from and to.
 
94
     
 
95
     if (to <= from)
 
96
          return (from);
 
97
          
 
98
     return (from + (float) lrand () / (LRAND_MAX / (to - from)));
 
99
}
 
100
 
 
101
// End random functions
 
102
 
 
103
void AnglesToVectors(vec angles, vec &forward, vec &right, vec &up)
 
104
{
 
105
     static float degrees_to_radians = 2 * PI / 360;
 
106
     float angle;
 
107
     float sin_pitch;
 
108
     float sin_yaw;
 
109
     float sin_roll;
 
110
     float cos_pitch;
 
111
     float cos_yaw;
 
112
     float cos_roll;
 
113
         
 
114
     // For some reason this has to be done :)
 
115
     // Me = math n00b
 
116
     angles.x = -angles.x;
 
117
     angles.y -= 90;
 
118
     
 
119
     // compute the sin and cosine of the pitch component
 
120
     angle = angles.x * degrees_to_radians;
 
121
     sin_pitch = sinf (angle);
 
122
     cos_pitch = cosf (angle);
 
123
     
 
124
     // compute the sin and cosine of the yaw component
 
125
     angle = angles.y * degrees_to_radians;
 
126
     sin_yaw = sinf (angle);
 
127
     cos_yaw = cosf (angle);
 
128
     
 
129
     // compute the sin and cosine of the roll component
 
130
     angle = angles.z * degrees_to_radians;
 
131
     sin_roll = sinf (angle);
 
132
     cos_roll = cosf (angle);
 
133
     
 
134
     // build the FORWARD vector
 
135
     forward.x = cos_pitch * cos_yaw;
 
136
     forward.y = cos_pitch * sin_yaw;
 
137
     forward.z = -sin_pitch;
 
138
     
 
139
     // build the RIGHT vector
 
140
     right.x = -(-(sin_roll * sin_pitch * cos_yaw) - (cos_roll * -sin_yaw));
 
141
     right.y = -(-(sin_roll * sin_pitch * sin_yaw) - (cos_roll * cos_yaw));
 
142
     right.z = -(sin_roll * cos_pitch);
 
143
     
 
144
     // build the UPWARDS vector
 
145
     up.x = ((cos_roll * sin_pitch * cos_yaw) - (sin_roll * -sin_yaw));
 
146
     up.y = ((cos_roll * sin_pitch * sin_yaw) - (sin_roll * cos_yaw));
 
147
     up.z = cos_roll * cos_pitch;
 
148
     
 
149
     return;
 
150
}
 
151
 
 
152
// Function code by PMB - End
 
153
 
 
154
float WrapXAngle(float angle)
 
155
{
 
156
     if (angle > 90) angle = 90;
 
157
     else if (angle < -90) angle = -90;
 
158
 
 
159
     return angle;
 
160
}
 
161
 
 
162
float WrapYZAngle(float angle)
 
163
{
 
164
     while (angle >= 360.0f) angle -= 360.0f;
 
165
     while (angle < 0.0f) angle += 360.0f;
 
166
 
 
167
     return angle;
 
168
}
 
169
 
 
170
// Sees how far it can come from 'from' to 'to' and puts the end vector in 'end'
 
171
// (1337 description :-)
 
172
// UNDONE: Optimize this as much as possible
 
173
void TraceLine(vec from, vec to, dynent *pTracer, bool CheckPlayers, traceresult_s *tr,
 
174
               bool SkipTags)
 
175
{
 
176
     tr->end = from;
 
177
     tr->collided = false;
 
178
     
 
179
     static float flNearestDist, flDist;
 
180
     static vec v;
 
181
     static bool solid;
 
182
    
 
183
     flNearestDist = 9999.0f;
 
184
     
 
185
     if(OUTBORD((int)from.x, (int)from.y)) return;
 
186
   
 
187
     // Check if the 'line' collides with entities like mapmodels
 
188
     loopv(ents)
 
189
     {
 
190
          entity &e = ents[i];
 
191
          if(e.type!=MAPMODEL) continue; // Only check map models for now
 
192
               
 
193
          mapmodelinfo &mmi = getmminfo(e.attr2);
 
194
          if(!&mmi || !mmi.h) continue;
 
195
    
 
196
          float lo = (float)(S(e.x, e.y)->floor+mmi.zoff+e.attr3);
 
197
          float hi = lo+mmi.h;
 
198
          float z = (fabs(from.z-lo) < fabs(from.z-hi)) ? lo : hi;           
 
199
          makevec(&v, e.x, e.y, z);          
 
200
          flDist = GetDistance(from, v); 
 
201
               
 
202
          if ((flDist < flNearestDist) && (intersect(&e, from, to, &tr->end)))
 
203
          {
 
204
               flNearestDist = GetDistance(from, tr->end);
 
205
               tr->collided = true;
 
206
          }
 
207
     }
 
208
 
 
209
     if (CheckPlayers)
 
210
     {
 
211
          // Check if the 'line' collides with players
 
212
          loopv(players)
 
213
          {
 
214
               playerent *d = players[i];
 
215
               if(!d || (d==pTracer) || (d->state != CS_ALIVE)) continue; // Only check valid players
 
216
                    
 
217
               flDist = GetDistance(from, d->o); 
 
218
               
 
219
               if ((flDist < flNearestDist) && (intersect(d, from, to, &tr->end)))
 
220
               {
 
221
                    flNearestDist = flDist;
 
222
                    tr->collided = true;
 
223
               }
 
224
          }
 
225
 
 
226
          // Check if the 'line' collides with the local player(player1)
 
227
          playerent *d = player1; // Shortcut
 
228
          if (d && (d!=pTracer) && !BotManager.m_pBotToView && (d->state == CS_ALIVE))
 
229
          {
 
230
               flDist = GetDistance(from, d->o); 
 
231
               
 
232
               if ((flDist < flNearestDist) && (intersect(d, from, to, &tr->end)))
 
233
               {
 
234
                    flNearestDist = flDist;
 
235
                    tr->collided = true;
 
236
               }
 
237
          }          
 
238
     }
 
239
    
 
240
    
 
241
     float dx = to.x-from.x;
 
242
     float dy = to.y-from.y; 
 
243
     int steps = (int)(sqrt(dx*dx+dy*dy)/0.9);
 
244
     if(!steps) // If from and to are on the same cube...
 
245
     {
 
246
          if (GetDistance(from, to) < flNearestDist)         
 
247
          {
 
248
               tr->end = to;
 
249
               sqr *s = S(int(from.x), int(from.y));
 
250
               float flr = GetCubeFloor(int(from.x), int(from.y));
 
251
               solid = ((!SkipTags || !s->tag) && SOLID(s));
 
252
               if (solid || (to.z < flr) || (to.z > s->ceil))
 
253
               {
 
254
                    tr->collided = true;
 
255
                    tr->end.z = (fabs(to.z-s->ceil) < fabs(to.z-flr)) ? s->ceil : flr;
 
256
               }
 
257
          }
 
258
          return;
 
259
     }
 
260
     
 
261
     float x = from.x;
 
262
     float y = from.y;
 
263
     int i = 0;
 
264
     vec endcube = from;
 
265
     
 
266
     // Now check if the 'line' is hit by a cube
 
267
     while(i<steps)
 
268
     {
 
269
          if(OUTBORD((int)x, (int)y)) break;
 
270
          if (GetDistance(from, endcube) >= flNearestDist) break;
 
271
          sqr *s = S(int(x), int(y));
 
272
          solid = ((!SkipTags || !s->tag) && SOLID(s));
 
273
          if(solid) break;
 
274
          float floor = s->floor;
 
275
          if(s->type==FHF) floor -= s->vdelta/4.0f;
 
276
          float ceil = s->ceil;
 
277
          if(s->type==CHF) ceil += s->vdelta/4.0f;
 
278
          float rz = from.z-((from.z-to.z)*(i/(float)steps));
 
279
          if(rz<floor || rz>ceil) break;
 
280
        
 
281
          endcube.x = x;
 
282
          endcube.y = y;
 
283
          endcube.z = rz;
 
284
          x += dx/(float)steps;
 
285
          y += dy/(float)steps;
 
286
          i++;
 
287
     }
 
288
    
 
289
     if ((i>=steps) && !tr->collided)
 
290
     {
 
291
          tr->end = to;
 
292
     }
 
293
     else
 
294
     {
 
295
          tr->collided = true;
 
296
          if (GetDistance(from, endcube) < flNearestDist)
 
297
               tr->end = endcube;
 
298
     }
 
299
 
 
300
     return;
 
301
}
 
302
 
 
303
float GetDistance(vec v1, vec v2)
 
304
{
 
305
     if ((v1.x == 0) && (v2.x == 0) && (v1.y == 0) && (v2.y == 0) && (v1.z == 0) &&
 
306
         (v2.z == 0))
 
307
          return 0.0f;
 
308
          
 
309
     return v1.dist(v2);
 
310
}
 
311
 
 
312
// As GetDistance(), but doesn take height in account.
 
313
float Get2DDistance(vec v1, vec v2)
 
314
{
 
315
     if ((v1.x == 0) && (v2.x == 0) && (v1.y == 0) && (v2.y == 0))
 
316
          return 0.0f;
 
317
     
 
318
     v1.z = v2.z = 0.0f;
 
319
     return v1.dist(v2);
 
320
}
 
321
 
 
322
bool IsVisible(vec v1, vec v2, dynent *tracer, bool SkipTags)
 
323
{
 
324
     traceresult_s tr;
 
325
     TraceLine(v1, v2, tracer, (tracer!=NULL), &tr, SkipTags);
 
326
     return !tr.collided;
 
327
}
 
328
 
 
329
// Prediction:
 
330
// - pos: Current position
 
331
// - vel: Current velocity
 
332
// - Time: In seconds, predict how far it is in Time seconds
 
333
vec PredictPos(vec pos, vec vel, float Time)
 
334
{
 
335
     float flVelLength = vel.magnitude();
 
336
    
 
337
     if (flVelLength <= 1.0)
 
338
          return pos; // don't bother with low velocities...
 
339
 
 
340
     vec v_end = vel;
 
341
     v_end.mul(Time);
 
342
     v_end.add(pos);
 
343
     return v_end;
 
344
}
 
345
 
 
346
// returns true if the given file is valid
 
347
bool IsValidFile(const char *szFileName)
 
348
{
 
349
     FILE *fp = fopen(szFileName, "r");
 
350
 
 
351
     if (fp)
 
352
     {
 
353
          fclose(fp);
 
354
          return true;
 
355
     }
 
356
 
 
357
     return false;
 
358
}
 
359
 
 
360
bool FileIsOlder(const char *szFileName1, const char *szFileName2)
 
361
{
 
362
/*     int file1, file2;
 
363
     struct stat stat1, stat2;
 
364
 
 
365
     file1 = open(szFileName1, O_RDONLY);
 
366
     file2 = open(szFileName2, O_RDONLY);
 
367
 
 
368
     fstat(file1, &stat1);
 
369
     fstat(file2, &stat2);
 
370
 
 
371
     close(file1);
 
372
     close(file2);
 
373
 
 
374
     return(stat1.st_mtime < stat2.st_mtime);*/ return false; // FIXME
 
375
}
 
376
 
 
377
vec Normalize(vec v)
 
378
{
 
379
     float flLen = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
 
380
     static vec v_norm = g_vecZero;
 
381
     if (flLen == 0) 
 
382
     {
 
383
          v_norm.x=0;v_norm.y=0;v_norm.z=1;
 
384
     }
 
385
     else
 
386
     {
 
387
          flLen = 1 / flLen;
 
388
          v_norm.x = v.x * flLen; v_norm.y = v.y * flLen; v_norm.z = v.z * flLen;
 
389
     }
 
390
     return v_norm;
 
391
}
 
392
 
 
393
float GetYawDiff(float curyaw, vec v1, vec v2)
 
394
{
 
395
     float yaw = -(float)atan2(v2.x - v1.x, v2.y - v1.y)/PI*180+180;    
 
396
     return yaw-curyaw;
 
397
}
 
398
 
 
399
vec CrossProduct(const vec &a, const vec &b)
 
400
{
 
401
     vec cross(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
 
402
     return cross;
 
403
}
 
404
 
 
405
int GetDirection(const vec &angles, const vec &v1, const vec &v2)
 
406
{
 
407
     vec tmp, forward, right, up, cross;
 
408
     float flDot;
 
409
 
 
410
     AnglesToVectors(angles, forward, right, up);
 
411
 
 
412
     tmp = v2;
 
413
     tmp.sub(v1);
 
414
     tmp.z = 0.0f; // Make 2D
 
415
     tmp = Normalize(tmp);
 
416
     forward.z = 0; // Make 2D
 
417
          
 
418
     flDot = tmp.dot(forward);
 
419
     cross = CrossProduct(tmp, forward);
 
420
     
 
421
     int Dir = DIR_NONE;
 
422
               
 
423
     if (cross.z > 0.1f) Dir |= LEFT;
 
424
     else if (cross.z < -0.1f) Dir |= RIGHT;
 
425
     if (flDot < -0.1f) Dir |= BACKWARD;
 
426
     else if (flDot > 0.1f) Dir |= FORWARD;
 
427
     
 
428
     if (v1.z > v2.z) Dir |= DOWN;
 
429
     if (v1.z < v2.z) Dir |= UP;
 
430
     
 
431
     return Dir;
 
432
}
 
433
 
 
434
float GetCubeFloor(int x, int y)
 
435
{
 
436
     sqr *s = S(x, y);
 
437
     float floor = s->floor;
 
438
     if (s->type == FHF)
 
439
          floor -= (s->vdelta+S(x+1,y)->vdelta+S(x,y+1)->vdelta+S(x+1,y+1)->vdelta)/16.0f;
 
440
     return floor;
 
441
}
 
442
 
 
443
float GetCubeHeight(int x, int y)
 
444
{
 
445
     sqr *s = S(x, y);
 
446
     float ceil = s->ceil;
 
447
     if(s->type == CHF)
 
448
          ceil += (s->vdelta+S(x+1,y)->vdelta+S(x,y+1)->vdelta+S(x+1,y+1)->vdelta)/16.0f;
 
449
     return ceil;
 
450
}
 
451
 
 
452
const char *SkillNrToSkillName(short skillnr)
 
453
{
 
454
     if (skillnr == 0) return "best";
 
455
     else if (skillnr == 1) return "good";
 
456
     else if (skillnr == 2) return "medium";
 
457
     else if (skillnr == 3) return "worse";
 
458
     else if (skillnr == 4) return "bad";
 
459
     
 
460
     return NULL;
 
461
}
 
462
 
 
463
bool IsInGame(dynent *d)
 
464
{
 
465
     if (!d) return false;
 
466
     
 
467
     if (d->type==ENT_BOT)
 
468
     {
 
469
          loopv(bots)
 
470
          {
 
471
               if (bots[i] == d)
 
472
                    return true;
 
473
          }
 
474
     }
 
475
     else
 
476
     {
 
477
          if (d == player1)
 
478
               return true;
 
479
          else
 
480
          {
 
481
               loopv(players)
 
482
               {
 
483
#ifdef VANILLA_CUBE               
 
484
                    if (!players[i] || (players[i]->state == CS_DEDHOST)) continue;
 
485
#elif defined(AC_CUBE)
 
486
                    if (!players[i]) continue;
 
487
#endif                    
 
488
                    if (players[i] == d)
 
489
                         return true;
 
490
               }
 
491
          }
 
492
     }
 
493
     return false;
 
494
}