~collinp/paradise-netrek/3.1p0

« back to all changes in this revision

Viewing changes to src/daemon/player.c

  • Committer: Collin Pruitt
  • Date: 2009-05-22 04:40:09 UTC
  • Revision ID: collinp111@gmail.com-20090522044009-gw30zywb9oaae4nr
Initial upload - just the source release of 3.1p0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*------------------------------------------------------------------
 
2
  Copyright 1989                Kevin P. Smith
 
3
                                Scott Silvey
 
4
 
 
5
Permission to use, copy, modify, and distribute this
 
6
software and its documentation for any purpose and without
 
7
fee is hereby granted, provided that the above copyright
 
8
notice appear in all copies.
 
9
 
 
10
  NETREK II -- Paradise
 
11
 
 
12
  Permission to use, copy, modify, and distribute this software and
 
13
  its documentation, or any derivative works thereof,  for any 
 
14
  NON-COMMERCIAL purpose and without fee is hereby granted, provided
 
15
  that this copyright notice appear in all copies.  No
 
16
  representations are made about the suitability of this software for
 
17
  any purpose.  This software is provided "as is" without express or
 
18
  implied warranty.
 
19
 
 
20
        Xtrek Copyright 1986                    Chris Guthrie
 
21
        Netrek (Xtrek II) Copyright 1989        Kevin P. Smith
 
22
                                                Scott Silvey
 
23
        Paradise II (Netrek II) Copyright 1993  Larry Denys
 
24
                                                Kurt Olsen
 
25
                                                Brandon Gillespie
 
26
                                Copyright 2000  Bob Glamm
 
27
 
 
28
--------------------------------------------------------------------*/
 
29
 
 
30
#include <math.h>
 
31
#include "config.h"
 
32
#include "proto.h"
 
33
#include "daemonII.h"
 
34
#include "data.h"
 
35
#include "shmem.h"
 
36
 
 
37
/*-----------------------------NUMBER DEFINES----------------------------*/
 
38
 /* defines dealing with ships exploding */
 
39
#define MAXDAMDIST 3000         /* range at which shipexplosions do damage */
 
40
 
 
41
 /* other defines */
 
42
#define YRANGE ((100000)/7)     /* range yellow alert comes on */
 
43
#define RRANGE ((100000)/10)    /* range red alert comes on */
 
44
 
 
45
 
 
46
#define DOCKDAMAGE      10      /* the amount of damage inflicted when you
 
47
                                   lose a docking ring... */
 
48
 
 
49
/*-----------------------------------------------------------------------*/
 
50
 
 
51
/*---------------------------EXTERNAL GLOBALS-----------------------------*/
 
52
/* from daemonII.c */
 
53
extern int ticks;
 
54
extern int dietime;
 
55
/* this doesn't look like it's used BUT check the definition of NotTmode 
 
56
   in daemonII.h */
 
57
extern int tourntimestamp;
 
58
 
 
59
/*---------------------------INTERNAL FUNCTIONS---------------------------*/
 
60
 
 
61
/*-----------------------------BEAMMEUPSCOTTY-----------------------------*/
 
62
/*  This function does the beamup for a player.  It allows the player
 
63
to beam up all the armies on a planet.  */
 
64
 
 
65
static void 
 
66
beammeupscotty(struct player *j)        /* the player beaming */
 
67
{
 
68
    struct planet *l;           /* to point to planet beaming from */
 
69
 
 
70
    if (j->p_flags & PFORBIT) { /* if orbiting a planet */
 
71
        l = &planets[j->p_planet];      /* get planet player is beaming from */
 
72
        if (l->pl_armies == 0   /* cannot beam if no armies */
 
73
        /* this prevents you from beaming up outside T-mode in a league game */
 
74
            || (!(configvals->evacuation) && (l->pl_armies < 5))
 
75
            || (status2->league && !status->tourn)
 
76
            || j->p_armies >= j->p_ship.s_maxarmies
 
77
            || ((j->p_ship.s_nflags & SFNARMYNEEDKILL)
 
78
           && (j->p_armies >= (int) (j->p_kills * j->p_ship.s_armyperkill)))
 
79
            ) {
 
80
            j->p_flags &= ~PFBEAMUP;
 
81
            return;             /* max armies for number of kills? */
 
82
        }
 
83
        if (l->pl_owner != j->p_team)
 
84
            return;             /* no picking up foreign troops */
 
85
 
 
86
        tlog_beamup(l, j);
 
87
 
 
88
        if (j->p_ship.s_nflags & SFNHASFIGHTERS) {
 
89
            j->p_ship.s_missilestored = j->p_ship.s_missilestored + FAE_RATE;
 
90
            j->p_armies = (int) (j->p_ship.s_missilestored / FAE_RATE);
 
91
        }
 
92
        else
 
93
            j->p_armies++;      /* pick an army up */
 
94
 
 
95
        l->pl_armies--;         /* dec armies on planet */
 
96
        l->pl_tinfo[j->p_team].armies = l->pl_armies;   /* update info */
 
97
        l->pl_tinfo[j->p_team].timestamp = status->clock;       /* timestamp it */
 
98
 
 
99
        if (l->pl_armies == 0) {/* if we beamed them all up then */
 
100
            l->pl_tinfo[l->pl_owner].owner = NOBODY;    /* no longer owner */
 
101
            /* these penalties apply even outside of T-mode */
 
102
            j->p_stats.st_tplanets--;   /* prevent scumming */
 
103
 
 
104
            j->p_stats.st_di -= 0.25;
 
105
            if (j->p_stats.st_di < 0.0)
 
106
                j->p_stats.st_di = 0.0;
 
107
 
 
108
            j->p_kills -= 0.25;
 
109
            if (j->p_kills < 0.0)
 
110
                j->p_kills = 0.0;
 
111
 
 
112
            tlog_planaban(l, j);
 
113
 
 
114
            l->pl_owner = NOBODY;       /* planet goes to nobody */
 
115
            checkwin(enemy_admiral(j->p_no));   /* check for winner */
 
116
        }
 
117
        if (j->p_lastman == 2)  /* KAO */
 
118
            /* j->p_flags &= ~PFBEAMUP; */
 
119
            j->p_lastman = 1;
 
120
 
 
121
    }
 
122
    else if (j->p_flags & PFDOCK) {     /* else if docked to another ship */
 
123
       if (players[j->p_docked].p_armies == 0
 
124
           || j->p_armies >= j->p_ship.s_maxarmies
 
125
           || ((j->p_ship.s_nflags & SFNARMYNEEDKILL)
 
126
            && (j->p_armies >= (int)(j->p_kills * j->p_ship.s_armyperkill))))
 
127
        {
 
128
           j->p_flags &= ~PFBEAMUP;
 
129
           return;
 
130
        }
 
131
 
 
132
        tlog_Bbeamup(&players[j->p_docked], j);
 
133
 
 
134
        if (j->p_ship.s_nflags & SFNHASFIGHTERS) {
 
135
            j->p_ship.s_missilestored = j->p_ship.s_missilestored + FAE_RATE;
 
136
            j->p_armies = (int) (j->p_ship.s_missilestored / FAE_RATE);
 
137
        }
 
138
        else {
 
139
            j->p_armies++;      /* add to armies */
 
140
            players[j->p_docked].p_armies--;    /* subtract from dockee */
 
141
        }
 
142
    }
 
143
}
 
144
 
 
145
 
 
146
 
 
147
 
 
148
/*-------------------------------BEAMDOWN---------------------------------*/
 
149
/*  This function beams armies down to a planet or to a ship the player
 
150
is dowcked on.  This function also has Kurt's mod for beaming while at
 
151
different alert statuses.  You get more stats from taking while alert status
 
152
is red than green.  */
 
153
 
 
154
static void 
 
155
beamdown(struct player *j)      /* the player beaming */
 
156
{
 
157
    char    buf[90];            /* to sprintf into */
 
158
    char    buf1[90];
 
159
    struct planet *l;           /* the planet beaming to */
 
160
    /* int oldowner; */         /*to keep track of old planet owner */
 
161
 
 
162
    if (j->p_armies == 0)       /* player cannot beam down if */
 
163
        return;                 /* he has no armies */
 
164
 
 
165
    if (j->p_flags & PFORBIT) { /* if beaming to planet then */
 
166
 
 
167
        l = &planets[j->p_planet];      /* get planet beaming to */
 
168
        /* oldowner = l->pl_owner; */   /*record old owner */
 
169
        if ((!((j->p_swar | j->p_hostile) & l->pl_owner))
 
170
            && (j->p_team != l->pl_owner) && (l->pl_owner != NOBODY))
 
171
            return;             /* no beaming down if not hostile */
 
172
 
 
173
        tlog_beamdown(l, j);
 
174
 
 
175
        if (l->pl_owner == j->p_team) { /* if beaming to own planet */
 
176
            if ((j->p_ship.s_nflags & SFNHASFIGHTERS) &&
 
177
                (j->p_ship.s_missilestored >= FAE_RATE)) {
 
178
                j->p_ship.s_missilestored = j->p_ship.s_missilestored - FAE_RATE;
 
179
                j->p_armies = (int) (j->p_ship.s_missilestored / FAE_RATE);
 
180
            }
 
181
            else
 
182
                j->p_armies--;  /* decrease by one army */
 
183
 
 
184
            l->pl_armies++;     /* increase planet armies */
 
185
            l->pl_tinfo[j->p_team].armies = l->pl_armies;
 
186
            l->pl_tinfo[j->p_team].timestamp = status->clock;
 
187
        }
 
188
        else {                  /* else beaming to foreign planet */
 
189
            j->p_swar |= l->pl_owner;   /* start war if necessay */
 
190
            j->p_armies--;      /* beam an army down */
 
191
            /* the defender might get a chance to destroy beamed-down
 
192
               army.  Check configvals. */
 
193
            if(l->pl_armies > 0 && (l->pl_flags & PLRESMASK) && 
 
194
               configvals->army_defend_facilities > 0.0)
 
195
            {
 
196
              if(drand48() > configvals->army_defend_facilities)
 
197
                l->pl_armies--;
 
198
            }
 
199
            else if(l->pl_armies > 0 && !(l->pl_flags & PLRESMASK) &&
 
200
                    configvals->army_defend_bare > 0.0)
 
201
            {
 
202
              if(drand48() > configvals->army_defend_bare)
 
203
                l->pl_armies--;
 
204
            }
 
205
            else
 
206
              l->pl_armies--;
 
207
            l->pl_tinfo[j->p_team].armies = l->pl_armies;
 
208
            l->pl_tinfo[j->p_team].timestamp = status->clock;
 
209
            l->pl_tinfo[l->pl_owner].armies = l->pl_armies;
 
210
 
 
211
            credit_armiesbombed(j, 1, l);
 
212
 
 
213
            if (l->pl_armies == 0) {    /* if all armies knocked off */
 
214
                (void) sprintf(buf, "%s destroyed by %s (%s)", l->pl_name,
 
215
                               j->p_name, twoletters(j));
 
216
                (void) sprintf(buf1, "%-3s->%-3s", l->pl_name,
 
217
                               teams[l->pl_owner].shortname);
 
218
                pmessage(buf, l->pl_owner, MTEAM | MDEST, buf1);
 
219
                tlog_plandest(l, j);
 
220
                l->pl_tinfo[l->pl_owner].owner = NOBODY;
 
221
                l->pl_tinfo[l->pl_owner].timestamp = status->clock;
 
222
                l->pl_tinfo[j->p_team].owner = NOBODY;
 
223
                l->pl_tinfo[j->p_team].armies = 0;
 
224
                l->pl_tinfo[j->p_team].timestamp = status->clock;
 
225
                l->pl_owner = NOBODY;
 
226
                l->pl_trevolt = 0;      /* stop revolution */
 
227
                if (NotTmode(ticks)) {  /* if not t-mode then */
 
228
                    rescue(STERMINATOR, j->p_no, l->pl_no);     /* send in the
 
229
                                                                   terminators */
 
230
                    rescue(STERMINATOR, j->p_no, l->pl_no);
 
231
                }
 
232
                checkwin(j->p_no);      /* check for genocide */
 
233
            }
 
234
            else if (l->pl_armies < 0) {        /* planet taken over */
 
235
                l->pl_armies *= -1;     /* newly taken planet has one army */
 
236
                if (status->tourn) {    /* if in t-mode then */
 
237
                    j->p_planets++;     /* inc game planets taken */
 
238
                    j->p_stats.st_tplanets++;   /* inc t-mode planets taken */
 
239
                    j->p_stats.st_di += 0.25;   /* inc DI for player */
 
240
                    status->planets++;  /* inc global planets */
 
241
 
 
242
                    if ((j->p_jsdock > 0) && (j->p_jsdock < 600)) {     /* give JS credit? */
 
243
                        struct player *js = &players[j->p_lastjs];      /* yes */
 
244
                        (void) sprintf(buf1, "%-3s->%s ", l->pl_name,
 
245
                                       twoletters(js));
 
246
                        (void) sprintf(buf, "Good assist, %s", js->p_name);
 
247
                        js->p_stats.st_jsplanets++;
 
248
                        
 
249
                        if(configvals->js_assist_credit)
 
250
                            js->p_stats.st_tplanets++;
 
251
 
 
252
                        status->jsplanets++;
 
253
                        pmessage(buf, j->p_lastjs, MINDIV | MTAKE, buf1);
 
254
                    }
 
255
 
 
256
                    j->p_kills += 0.25; /* inc kills for taking planet */
 
257
                    checkmaxkills(j->p_no);     /* check max kills */
 
258
                }
 
259
                (void) sprintf(buf, "%s taken over by %s (%s)", l->pl_name,
 
260
                               j->p_name, twoletters(j));
 
261
                l->pl_owner = j->p_team;        /* switch owner */
 
262
                tlog_plantake(l, j);
 
263
                l->pl_hinfo |= j->p_team;       /* set up info */
 
264
                l->pl_tinfo[j->p_team].owner = l->pl_owner;
 
265
                l->pl_tinfo[j->p_team].armies = l->pl_armies;
 
266
                l->pl_tinfo[j->p_team].flags = l->pl_flags;
 
267
                l->pl_tinfo[j->p_team].timestamp = status->clock;
 
268
                checkwin(j->p_no);      /* check for win */
 
269
                (void) sprintf(buf1, "%-3s->%-3s", l->pl_name, teams[l->pl_owner].shortname);
 
270
                pmessage(buf, l->pl_owner, MTEAM | MTAKE, buf1);
 
271
            }
 
272
        }
 
273
    }                           /* end of beaming to foreign planets */
 
274
    else if (j->p_flags & PFDOCK) {     /* if beaming to ship docked to */
 
275
        if (players[j->p_docked].p_team != j->p_team)
 
276
            return;             /* no beaming to foreign dockees */
 
277
        if (players[j->p_docked].p_armies ==
 
278
            players[j->p_docked].p_ship.s_maxarmies)
 
279
            return;             /* no beaming over max armies */
 
280
        tlog_Bbeamdown(&players[j->p_docked], j);
 
281
        j->p_armies--;          /* transfer one army over */
 
282
        players[j->p_docked].p_armies++;
 
283
    }
 
284
}
 
285
 
 
286
 
 
287
 
 
288
/*----------------------------------BLOWUP--------------------------------*/
 
289
/*  This function does the explosion damage of a ship explosion.  It
 
290
inflicts damage on the nearby players.  The damage has been changed to be
 
291
based on the amount of fuel the ship has when it explodes.  */
 
292
 
 
293
static void 
 
294
blowup(struct player *sh)       /* the player that blew up */
 
295
{
 
296
    register int i;             /* looping vars */
 
297
    int     dx, dy;             /* delta coords of a ship */
 
298
    double  dist2;              /* for distance of ship (sqared) */
 
299
    double  maxdist, maxdist2;  /* to hold max damage dist */
 
300
    int     damage;             /* to hold calculated damage */
 
301
    register struct player *j;  /* to point to other players */
 
302
    double  ft, expl;           /* floating point temp */
 
303
 
 
304
 
 
305
    /* moved some of this stuff out of the for loop... */
 
306
    maxdist = sqrt((double) MAX(sh->p_fuel, 0) / 6.0) * 20.0;
 
307
    if (maxdist > MAXDAMDIST)
 
308
        maxdist = MAXDAMDIST;
 
309
    maxdist2 = maxdist * maxdist;
 
310
 
 
311
    expl = (double) ((sh->p_ship.s_expldam
 
312
                      + sqrt(MAX(sh->p_fuel, 0) / (double) sh->p_ship.s_maxfuel) * sh->p_ship.s_fueldam)
 
313
                     / get_explode_views(sh->p_ship.s_type));
 
314
 
 
315
    if (sh->p_whydead == KGHOST)
 
316
        return;                 /* no gostbusted ships blowing up */
 
317
 
 
318
    for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
 
319
        struct player   *me;
 
320
        if ((j->p_status != PALIVE) || (sh == j))       /* player no alive or is
 
321
                                                           same */
 
322
            continue;           /* as exploding ship, then continue */
 
323
        me = sh;                /* for friendlyPlayer macro below */
 
324
        if ((sh->p_whydead == KQUIT) && (friendlyPlayer(j)))
 
325
            continue;           /* No quiting to blow up on people */
 
326
        dx = sh->p_x - j->p_x;  /* delta coords */
 
327
        dy = sh->p_y - j->p_y;
 
328
        if ((ABS(dx) > (int) maxdist) || (ABS(dy) > (int) maxdist))
 
329
            continue;           /* continue if obviously too far away */
 
330
        dist2 = (double) dx *(double) dx + (double) dy *(double) dy;
 
331
        if (dist2 >= maxdist2)  /* if too far away to damage */
 
332
            continue;           /* then check next player */
 
333
 
 
334
        ft = sqrt(1.0 - dist2 / maxdist2);
 
335
        damage = (int) (expl * ft);     /* scale by distance */
 
336
        if (damage > 0) {       /* if damage done then */
 
337
            /*
 
338
               inflict damage, and maybe credit the person who killed us if
 
339
               we cause the death of a teammate
 
340
            */
 
341
            inflict_damage(sh, &players[sh->p_whodead], j, damage, KSHIP);
 
342
        }
 
343
    }
 
344
}
 
345
 
 
346
 
 
347
 
 
348
 
 
349
/*--------------------------------DOSHIPEXPLODE---------------------------*/
 
350
/*  This function makes a ship explode.  It resets various fields in the
 
351
players structure and decs the timer before the player's explosion is done
 
352
and he is really dead.  */
 
353
 
 
354
static void 
 
355
doshipexplode(struct player *j) /* the player to explode */
 
356
{
 
357
    int     k;                  /* another damned looping var */
 
358
 
 
359
    j->p_flags &= ~PFCLOAK;     /* the cloaking device is kaputt */
 
360
 
 
361
    blowup(j);                  /* damage surrounding players */
 
362
 
 
363
    if (--j->p_explode <= 0) {  /* dec explode timer until really gone */
 
364
        j->p_status = PDEAD;    /* explosion done--make player dead */
 
365
        j->p_explode = 600 / PLAYERFUSE;        /* set timer for ghost buster */
 
366
    }
 
367
    undock_player(j);           /* if player docked then undock him */
 
368
 
 
369
    if (allows_docking(j->p_ship)) {    /* if ships can dock */
 
370
        for (k = 0; k < j->p_ship.s_numports; k++)      /* remove all docked
 
371
                                                           ships */
 
372
            base_undock(j, k);
 
373
        j->p_docked = 0;        /* no ships docked anymore */
 
374
    }
 
375
    if (j->p_flags & PFORBIT) { /* if orbiting then */
 
376
        j->p_flags &= ~PFORBIT; /* eject him from orbit */
 
377
    }                           /* reset ship timers */
 
378
    if (j->p_status == PDEAD) {
 
379
        /*
 
380
           this is the last time doshipexplode will be called for this
 
381
           player. increment the rebuild timer
 
382
        */
 
383
        if ((j->p_whydead == KSHIP) || (j->p_whydead == KTORP)
 
384
            || (j->p_whydead == KPHASER) || (j->p_whydead == KPLASMA)
 
385
            || (j->p_whydead == KPLANET) || (j->p_whydead == KGENOCIDE))
 
386
            /* we have to build ANOTHER one */
 
387
            if (status->tourn
 
388
                || configvals->affect_shiptimers_outside_T)
 
389
                teams[j->p_team].s_turns[j->p_ship.s_type] += j->p_ship.s_timer;
 
390
    }
 
391
}
 
392
 
 
393
 
 
394
 
 
395
 
 
396
/*----------------------------------DOORBIT--------------------------------*/
 
397
/*  This function makes a player orbit around a planet by adjusting his
 
398
coordinates to go around in a circle.   */
 
399
 
 
400
static void 
 
401
doorbit(struct player *j)       /* the player in orbit */
 
402
{
 
403
    int     x, y;
 
404
    int     angle;
 
405
 
 
406
    if (j->p_orbitdir)
 
407
        j->p_dir += 2;          /* make player rotate */
 
408
    else
 
409
        j->p_dir -= 2;          /* make player rotate */
 
410
 
 
411
    j->p_desdir = j->p_dir;
 
412
 
 
413
    angle = j->p_dir + (j->p_orbitdir ? -64 : 64);
 
414
    x = planets[j->p_planet].pl_x + ORBDIST     /* new x coord */
 
415
        * Cos[(unsigned char) angle];
 
416
    y = planets[j->p_planet].pl_y + ORBDIST     /* new y coord */
 
417
        * Sin[(unsigned char) angle];
 
418
    move_player(j->p_no, x, y, 1);
 
419
}
 
420
 
 
421
 
 
422
static void 
 
423
repair_docking_ring(struct player *j)
 
424
{
 
425
    int     i;
 
426
    int     damaged = 0;
 
427
    for (i = 0; i < j->p_ship.s_numports; i++) {
 
428
        if (j->p_port[i] == PDAMAGE)
 
429
            damaged++;
 
430
    }
 
431
    /* check to see if we've repaired any docking ring damage */
 
432
    for (i = 0;
 
433
    (damaged - 1) * DOCKDAMAGE + 1 > j->p_damage && i < j->p_ship.s_numports;
 
434
         i++) {
 
435
        if (j->p_port[i] == PDAMAGE) {
 
436
            j->p_port[i] = VACANT;
 
437
            damaged--;
 
438
        }
 
439
    }
 
440
}
 
441
 
 
442
/*---------------------------------DORESOURCES----------------------------*/
 
443
/*  This function adjusts various things on a ship, like the fuel regen-
 
444
eration, repair, etc.  Some changes:  fuel cost of cloaking is based on
 
445
the speed of the ship.  There is a ver for how fast each ship can take on
 
446
fuel from  a planet of other ship  */
 
447
 
 
448
static void 
 
449
doresources(struct player *j)   /* the player in orbit */
 
450
{
 
451
    int     factor;
 
452
    int     ccost;
 
453
    /* Charge for shields */
 
454
    if (j->p_flags & PFSHIELD)
 
455
        j->p_fuel -= j->p_ship.s_shieldcost;
 
456
 
 
457
    /* cool weapons */
 
458
    j->p_wtemp -= j->p_ship.s_wpncoolrate;      /* subract from W-temp */
 
459
    if (j->p_wtemp < 0)         /* no going below zero */
 
460
        j->p_wtemp = 0;
 
461
    if (j->p_flags & PFWEP) {   /* if weapon temped */
 
462
        if (--j->p_wtime <= 0)  /* then w-tep ends when */
 
463
            j->p_flags &= ~PFWEP;       /* w timer goes to zero */
 
464
    }
 
465
    else if (j->p_wtemp > j->p_ship.s_maxwpntemp) {     /* weapons too hot? */
 
466
        if (!(lrand48() % 40)) {/* chance to turn on W-temp */
 
467
            j->p_flags |= PFWEP;/* W-temp the poor sucker */
 
468
            j->p_wtime = ((lrand48() % 150) + 100) / PLAYERFUSE;
 
469
        }
 
470
    }
 
471
    /* cool engine */
 
472
    j->p_etemp -= j->p_ship.s_egncoolrate;      /* cool the engine */
 
473
    if (j->p_etemp < 0)         /* no going below zero */
 
474
        j->p_etemp = 0;
 
475
    if (j->p_flags & PFENG) {   /* if E-temped */
 
476
        /* see if timer has expired and we're not hot.  if we don't
 
477
         * check for current temp, PFENG will blink on and off and
 
478
         * you can actually move in a bursty fashion :) */
 
479
        if ( (--j->p_etime <= 0) && !(j->p_etemp > j->p_ship.s_maxegntemp) )
 
480
            j->p_flags &= ~PFENG;       /* turn off E-temp if need be */
 
481
    }
 
482
    else if (j->p_etemp > j->p_ship.s_maxegntemp) {     /* engine too hot? */
 
483
        if (!(lrand48() % 20)) {/* random chance for E-temp */
 
484
            j->p_flags |= PFENG;/* set E-temp flag */
 
485
            j->p_etime = ((lrand48() % 150) + 100) / PLAYERFUSE;        /* set E-tmp timer */
 
486
            j->p_desspeed = 1;  /* desired speed goes to zero (one?) */
 
487
        }
 
488
    }
 
489
    if (configvals->newcloak)   /* cloak cost based on speed */
 
490
        ccost = (int) (((float) j->p_ship.s_cloakcost / 10.0) *
 
491
                        isqrt(j->p_speed + 1));
 
492
    else
 
493
        ccost = j->p_ship.s_cloakcost / 5;      /* 5 because regens have
 
494
                                                   been doubled since
 
495
                                                   bronco */
 
496
    if (j->p_flags & PFCLOAK) { /* do cloaking cost */
 
497
        if (j->p_fuel < ccost)  /* if not enough fuel */
 
498
            j->p_flags &= ~PFCLOAK;     /* then decloak */
 
499
        else
 
500
            j->p_fuel -= ccost;
 
501
    }
 
502
    /* add to fuel */
 
503
    if ((j->p_flags & PFORBIT)  /* if orbiting */
 
504
        &&(planets[j->p_planet].pl_flags & PLFUEL)      /* a fuel planet */
 
505
        &&(!(planets[j->p_planet].pl_owner              /* and not hostile */
 
506
             & (j->p_swar | j->p_hostile))))  {         /* or at war */
 
507
        j->p_fuel += j->p_ship.s_takeonfuel * 2;        /* then take on fuel */
 
508
        if( configvals->helpfulplanets )   {            /* helpful planets? */
 
509
            j->p_etemp -= j->p_ship.s_egncoolrate;      /* cool engine too */
 
510
            if( j->p_etemp < 0 )
 
511
                j->p_etemp = 0;
 
512
        }
 
513
    }   else if ((j->p_flags & PFORBIT)                 /* if orbiting */
 
514
             &&(!(planets[j->p_planet].pl_owner         /* and not hostile */
 
515
                  & (j->p_swar | j->p_hostile))))  {    /* or at war */
 
516
        if( configvals->helpfulplanets )   {            /* helpful planets? */
 
517
            j->p_etemp -= j->p_ship.s_egncoolrate;      /* cool engine too */
 
518
            if( j->p_etemp < 0 )
 
519
                j->p_etemp = 0;
 
520
            j->p_fuel += j->p_ship.s_takeonfuel;
 
521
            if( j->p_fuel > j->p_ship.s_maxfuel )
 
522
                j->p_fuel = j->p_ship.s_maxfuel;        /* don't let it run over */
 
523
        }   else
 
524
            j->p_fuel += j->p_ship.s_takeonfuel / 3;    /* then take on fuel */
 
525
    }   else if ((j->p_flags & PFDOCK)  /* if docked */
 
526
             &&(j->p_fuel < j->p_ship.s_maxfuel)) {     /* and room for fuel */
 
527
        struct player *base = &players[j->p_docked];
 
528
        if ((base->p_fuel > base->p_ship.s_mingivefuel) /* can't fuel below min */
 
529
            &&(base->p_ship.s_nflags & SFNCANFUEL)
 
530
            && (j->p_fuel < j->p_ship.s_maxfuel)) {
 
531
            j->p_fuel += j->p_ship.s_takeonfuel;        /* suck some fuel off */
 
532
            base->p_fuel -= j->p_ship.s_takeonfuel;
 
533
        }
 
534
    }
 
535
    /* else *//* if in free space */
 
536
    else if ((j->p_flags & PFDOCK)      /* if docked */
 
537
             &&(j->p_fuel >= j->p_ship.s_maxfuel) &&
 
538
             (j->p_ship.s_type == PATROL)) {
 
539
        if (j->p_ship.s_missilestored < shipvals[PATROL].s_missilestored) {
 
540
            struct player *base = &players[j->p_docked];
 
541
            base->p_fuel -= j->p_ship.s_missile.cost;
 
542
            j->p_ship.s_missilestored++;
 
543
        }
 
544
    }
 
545
    else
 
546
        j->p_fuel += j->p_ship.s_recharge;      /* add regen fuel */
 
547
 
 
548
    if (j->p_fuel > j->p_ship.s_maxfuel) {      /* over max fuel? */
 
549
        if (j->p_flags & PFDOCK) {
 
550
            struct player *base = &players[j->p_docked];
 
551
            if (base->p_fuel < base->p_ship.s_maxfuel) {        /* give excess to base */
 
552
                base->p_fuel += j->p_fuel - j->p_ship.s_maxfuel;
 
553
                if (base->p_fuel > base->p_ship.s_maxfuel)
 
554
                    base->p_fuel = base->p_ship.s_maxfuel;
 
555
            }
 
556
        }
 
557
        j->p_fuel = j->p_ship.s_maxfuel;        /* set to max */
 
558
    }
 
559
    if (j->p_fuel < 0) {        /* if below zero */
 
560
        j->p_desspeed = 0;      /* come to a stop */
 
561
        j->p_flags &= ~PFCLOAK; /* uncloak */
 
562
        j->p_fuel = 0;          /* set it to zero */
 
563
    }
 
564
    /* repair stuff */
 
565
    if (j->p_flags & PFREPAIR)
 
566
        factor = 2;
 
567
    else
 
568
        factor = 1;
 
569
    if ((j->p_flags & PFORBIT) && !((j->p_swar |
 
570
                           j->p_hostile) & planets[j->p_planet].pl_owner)) {
 
571
        switch (planets[j->p_planet].pl_flags & (PLREPAIR | PLSHIPYARD)) {
 
572
        case 0:
 
573
            factor += 1;
 
574
            break;
 
575
        case PLREPAIR:
 
576
            factor += 4;
 
577
            break;
 
578
        case PLSHIPYARD:
 
579
            factor += 2;
 
580
            break;
 
581
        case PLREPAIR | PLSHIPYARD:
 
582
            factor += 5;
 
583
            break;
 
584
        }
 
585
    }
 
586
    else if ((j->p_flags & PFDOCK) &&
 
587
             (players[j->p_docked].p_ship.s_nflags & SFNCANREPAIR)) {
 
588
        factor += 3;
 
589
    }
 
590
    if (j->p_shield < j->p_ship.s_maxshield) {  /* if shields damaged */
 
591
        /* repair the shields */
 
592
        j->p_subshield += j->p_ship.s_repair * factor;  /* add to shields fract */
 
593
 
 
594
        if (j->p_subshield / 1000) {    /* if fract over 1000 */
 
595
            j->p_shield += j->p_subshield / 1000;       /* then add to shields */
 
596
            j->p_subshield %= 1000;     /* take mod */
 
597
        }
 
598
        if (j->p_shield > j->p_ship.s_maxshield) {      /* went over max */
 
599
            j->p_shield = j->p_ship.s_maxshield;        /* then no overflow */
 
600
            j->p_subshield = 0;
 
601
        }
 
602
    }                           /* end of if shields damaged */
 
603
    /* do repair of ship */
 
604
    if (j->p_damage && !(j->p_flags & PFSHIELD)) {
 
605
        j->p_subdamage += j->p_ship.s_repair * factor;  /* add to fract repair */
 
606
        if (j->p_subdamage / 1000) {    /* if fract repair too high */
 
607
            j->p_damage -= j->p_subdamage / 1000;       /* take away real damage */
 
608
            j->p_subdamage %= 1000;     /* mod the fract repair */
 
609
        }
 
610
        if (j->p_damage < 0) {  /* do not want damge < 0 */
 
611
            j->p_damage = 0;    /* set it */
 
612
            j->p_subdamage = 0; /* zero the fract part too */
 
613
        }
 
614
    }
 
615
    if (allows_docking(j->p_ship))
 
616
        repair_docking_ring(j);
 
617
}
 
618
 
 
619
 
 
620
 
 
621
 
 
622
/*--------------------------------DOBOUNCE--------------------------------*/
 
623
/*  This function checks to see if the player has hit a wall.  If he has his
 
624
direction and position are adjusted.  */
 
625
 
 
626
static void 
 
627
dobounce(struct player *j)      /* the player to bounce */
 
628
{
 
629
    int     x = j->p_x;
 
630
    int     y = j->p_y;
 
631
    if (j->p_x < 0) {           /* past left wall? */
 
632
        x = -j->p_x;            /* set him to right of wall */
 
633
        j->p_dir = j->p_desdir = 64 - (j->p_dir - 192); /* adjust direction */
 
634
    }
 
635
    else if (j->p_x > configvals->gwidth) {     /* past right wall? */
 
636
        x = configvals->gwidth - (j->p_x - configvals->gwidth);
 
637
        /* set him left of wall */
 
638
        j->p_dir = j->p_desdir = 192 - (j->p_dir - 64); /* adjust direction */
 
639
    }
 
640
    if (j->p_y < 0) {           /* past top wall? */
 
641
        y = -j->p_y;            /* set inside galactic */
 
642
        j->p_dir = j->p_desdir = 128 - j->p_dir;        /* adjust direction */
 
643
    }
 
644
    else if (j->p_y > configvals->gwidth) {     /* below bottom wall */
 
645
        y = configvals->gwidth - (j->p_y - configvals->gwidth);
 
646
        /* place on right side of bed */
 
647
        j->p_dir = j->p_desdir = 0 - (j->p_dir - 128);  /* adjust position */
 
648
    }
 
649
    move_player(j->p_no, x, y, 1);
 
650
}
 
651
 
 
652
 
 
653
 
 
654
 
 
655
/*---------------------------------DOALERT-------------------------------*/
 
656
/*  This function sets the player's alert status by checking the other
 
657
players in the game and seeing if they are too close.  Should probably be
 
658
moved to the code that does visibility.  */
 
659
 
 
660
static void 
 
661
doalert(struct player *j)       /* the player to check for */
 
662
{
 
663
    int     k;                  /* Oh, no.  Another looping var */
 
664
    int     dx, dy, dist;       /* to find distances */
 
665
 
 
666
    j->p_flags |= PFGREEN;      /* default is green status */
 
667
    j->p_flags &= ~(PFRED | PFYELLOW);  /* clear red and yellow alert */
 
668
    for (k = 0; k < MAXPLAYER; k++) {   /* go through all players */
 
669
        if ((players[k].p_status != PALIVE)     /* should we check player */
 
670
            ||((!((j->p_swar | j->p_hostile) & players[k].p_team))
 
671
          && (!((players[k].p_swar | players[k].p_hostile) & j->p_team)))) {
 
672
            continue;           /* no, don't waste the time */
 
673
        }
 
674
        else if (j == &players[k])      /* do not check ourself */
 
675
            continue;
 
676
        else {                  /* we will check this player */
 
677
            dx = j->p_x - players[k].p_x;       /* take delta coords */
 
678
            dy = j->p_y - players[k].p_y;
 
679
            if (ABS(dx) > YRANGE || ABS(dy) > YRANGE)   /* obviously out of
 
680
                                                           yellow */
 
681
                continue;       /* stop checking him */
 
682
            dist = dx * dx + dy * dy;   /* calc dist squared */
 
683
            if ((dist < YRANGE * YRANGE)) {     /* close enough for yellow
 
684
                                                   alert? */
 
685
                j->p_flags |= PFYELLOW;
 
686
                j->p_flags &= ~(PFGREEN);
 
687
            }
 
688
            if (dist < RRANGE * RRANGE) {       /* if close enough for red
 
689
                                                   alert */
 
690
                j->p_flags |= PFRED;    /* set red alert status */
 
691
                j->p_flags &= ~(PFGREEN | PFYELLOW);
 
692
            }
 
693
            if (j->p_flags & PFRED)     /* if yellow set then check no */
 
694
                break;          /* further */
 
695
        }
 
696
    }
 
697
}
 
698
 
 
699
 
 
700
 
 
701
 
 
702
/*--------------------------------CHANGEDIR--------------------------------*/
 
703
/*  This function does the turning for a ship.  It changes the players
 
704
direction to his desired direction, with the rate of change based on the
 
705
player's speed and maneuveribility of his ship.  This function includes
 
706
optional use of TC's new-style turn rates.  */
 
707
 
 
708
static void 
 
709
changedir(struct player *sp)    /* the player to turn */
 
710
{
 
711
    unsigned int ch_ticks;
 
712
    unsigned int min, max;
 
713
    int     speed;
 
714
 
 
715
    speed = sp->p_speed;        /* get player's speed */
 
716
    if (speed == 0) {           /* if player is at speed zero then */
 
717
        sp->p_dir = sp->p_desdir;       /* change in direction is instant */
 
718
        sp->p_subdir = 0;
 
719
    }
 
720
    else {                      /* else we are moving */
 
721
        if (configvals->newturn)/* newstyle turn */
 
722
            sp->p_subdir += sp->p_ship.s_turns / (speed * speed);
 
723
        else                    /* old style turn */
 
724
            sp->p_subdir += sp->p_ship.s_turns / ((sp->p_speed < 30) ?
 
725
                                           (1 << sp->p_speed) : 1000000000);
 
726
        ch_ticks = sp->p_subdir / 1000; /* get upper digits of subdir */
 
727
        if (ch_ticks) {         /* if more than one then we turn */
 
728
            if (sp->p_dir > sp->p_desdir) {     /* find the min and max of
 
729
                                                   current */
 
730
                min = sp->p_desdir;     /* direction and desired direction */
 
731
                max = sp->p_dir;
 
732
            }
 
733
            else {
 
734
                min = sp->p_dir;
 
735
                max = sp->p_desdir;
 
736
            }
 
737
            if ((ch_ticks > max - min) || (ch_ticks > 256 - max + min)) /* can we immediately */
 
738
                sp->p_dir = sp->p_desdir;       /* get to desired direction */
 
739
            else if ((unsigned char) ((int) sp->p_dir - (int) sp->p_desdir) > 127)
 
740
                sp->p_dir += ch_ticks;  /* else move to the right */
 
741
            else
 
742
                sp->p_dir -= ch_ticks;  /* move to the left */
 
743
            sp->p_subdir %= 1000;       /* take off upper digits */
 
744
        }
 
745
    }
 
746
}
 
747
 
 
748
 
 
749
 
 
750
 
 
751
static int 
 
752
being_tractored(struct player *victim)
 
753
{
 
754
    int     i;
 
755
    for (i = 0; i < MAXPLAYER; i++)
 
756
        if (players[i].p_status == PALIVE
 
757
            && (players[i].p_flags & (PFTRACT | PFPRESS))
 
758
            && (players[i].p_tractor == victim->p_no)
 
759
            && (players[i].p_no != victim->p_no)        /* can happen */
 
760
            && (players[i].p_team != victim->p_team)
 
761
            )
 
762
            return 1;           /* DOH! */
 
763
 
 
764
    /* we made it! */
 
765
    return 0;
 
766
}
 
767
 
 
768
/*----------------------------------DOMOVE-------------------------------*/
 
769
/*  This function calls the change direction function then accellerates or
 
770
decellerates the ship if it is needed.  The coordinates of the ship are
 
771
then adjusted.  */
 
772
 
 
773
static void 
 
774
domove(struct player *j)        /* the player to move */
 
775
{
 
776
    int     maxspeed;           /* to hold max speed */
 
777
    int     acc;                /* to hold accelleration */
 
778
    int     dcc;                /* to hold decelleration */
 
779
    int     fcost;              /* to hold fuel cost */
 
780
    int     ecost;              /* to hold E-temp cost */
 
781
    float   t;                  /* temp float */
 
782
    int     k;                  /* looping var */
 
783
 
 
784
    /* warp drive */
 
785
    if (j->p_desspeed <= j->p_speed && j->p_speed <= j->p_ship.s_imp.maxspeed)
 
786
        j->p_flags &= ~(PFWARP | PFAFTER);
 
787
 
 
788
    if (j->p_warptime > 0
 
789
        && configvals->warpprepstyle == WPS_TABORTNOW
 
790
        && being_tractored(j)) {
 
791
        j->p_warptime = 0;      /* abort warp prep now */
 
792
        j->p_flags &= ~PFWARPPREP;
 
793
        god2player("Tractor beam aborted warp prep immediately", j->p_no);
 
794
    }
 
795
 
 
796
    if (j->p_warptime > 0 ||
 
797
        (configvals->warpprep_suspendable && j->p_flags & PFWPSUSPENDED)) {
 
798
        if (j->p_speed == j->p_ship.s_warpprepspeed     /* don't speed */
 
799
            && (configvals->cloakduringwarpprep /* is cloaking legal? */
 
800
                || !(j->p_flags & PFCLOAK))     /* or is it not engaged? */
 
801
            ) {
 
802
            if (configvals->warpprepstyle == WPS_TSUSPEND && being_tractored(j)) {
 
803
                /* whoa, warp prep suspended */
 
804
            }
 
805
            else {
 
806
                j->p_warptime--;/* countdown to warp powerup. */
 
807
                /* put off warping if warpprep suspended  [BDyess] */
 
808
                if (j->p_warptime == 0 && (j->p_flags & PFWPSUSPENDED) &&
 
809
                    configvals->warpprep_suspendable)
 
810
                    j->p_warptime = 1;
 
811
                if (0 == j->p_warptime) {
 
812
                    int     success = 1;
 
813
                    /* warp drives have finished prepping */
 
814
                    j->p_flags &= ~PFWARPPREP;
 
815
                    if (configvals->warpprepstyle == WPS_TABORT) {
 
816
                        if (being_tractored(j)) {
 
817
                            god2player("Tractor beam aborted warp engagement", j->p_no);
 
818
                            success = 0;
 
819
                        }
 
820
                    }
 
821
                    else if (configvals->warpprepstyle == WPS_TPREVENT) {
 
822
                        if (being_tractored(j)) {
 
823
                            j->p_warptime++;
 
824
                            success = 0;
 
825
                        }
 
826
                    }
 
827
                    if (success) {
 
828
                        j->p_flags |= PFWARP;
 
829
                        j->p_desspeed = j->p_warpdesspeed;      /* go however fast he
 
830
                                                                   asked for originally
 
831
                                                                   [BDyess] */
 
832
                    }
 
833
                }
 
834
            }
 
835
        }
 
836
        else {
 
837
            j->p_flags |= PFWARPPREP;
 
838
            j->p_desspeed = j->p_ship.s_warpprepspeed;
 
839
            if (!configvals->cloakduringwarpprep)
 
840
                j->p_flags &= ~PFCLOAK;
 
841
        }
 
842
    }
 
843
 
 
844
    /**********************************************************************/
 
845
    /*
 
846
     *  for some reason this would occasionally be zero and cause an FPE in
 
847
     *  the code below
 
848
     */
 
849
    if (!j->p_ship.s_maxdamage)
 
850
        return;
 
851
 
 
852
    if ((j->p_dir != j->p_desdir) && (j->p_status != PEXPLODE))
 
853
        changedir(j);           /* change direction if needed */
 
854
 
 
855
    if((j->p_flags & PFWARP) && !j->p_warptime && configvals->tractabortwarp)
 
856
        if(being_tractored(j))
 
857
            j->p_flags &= ~PFWARP;
 
858
 
 
859
    /* Alter speed */
 
860
    if ((j->p_flags & PFWARP) &&
 
861
        j->p_warptime == 0) {   /* make sure we are really warping */
 
862
        maxspeed = j->p_ship.s_warp.maxspeed;
 
863
        if(configvals->warpzone) {
 
864
          if(j->p_zone > 0)
 
865
            maxspeed = maxspeed * 3 / 2;
 
866
        }
 
867
        /* get damage adjusted max speed */
 
868
        maxspeed -= (int) ((float) maxspeed *
 
869
                   (float) j->p_damage / (float) j->p_ship.s_maxdamage);
 
870
        maxspeed = (maxspeed < 0) ? 0 : maxspeed;       /* no going backward */
 
871
        acc = j->p_ship.s_warp.acc;     /* get accelleration for warp */
 
872
        dcc = j->p_ship.s_warp.dec;     /* get decelleration for warp */
 
873
        fcost = j->p_ship.s_warp.cost;  /* get fuel for warping */
 
874
        ecost = j->p_ship.s_warp.etemp; /* get e-temp for warping */
 
875
    }
 
876
    else if (j->p_flags & PFAFTER) {    /* if after burners on */
 
877
        maxspeed = j->p_ship.s_after.maxspeed -
 
878
            (int) ((float) j->p_ship.s_after.maxspeed *
 
879
                   (float) j->p_damage / (float) j->p_ship.s_maxdamage);
 
880
        maxspeed = (maxspeed < 0) ? 0 : maxspeed;       /* no going backward */
 
881
        acc = j->p_ship.s_after.acc;    /* get acc for afterburners */
 
882
        dcc = j->p_ship.s_after.dec;    /* get decel for afterburners */
 
883
        fcost = j->p_ship.s_after.cost; /* fuel used for after */
 
884
        ecost = j->p_ship.s_after.etemp;        /* E-temp for after */
 
885
    }
 
886
    else {                      /* if normal speed */
 
887
        maxspeed = j->p_ship.s_imp.maxspeed - (int) ((float) j->p_ship.s_imp.maxspeed *
 
888
                       (float) j->p_damage / (float) j->p_ship.s_maxdamage);
 
889
        maxspeed = (maxspeed < 0) ? 0 : maxspeed;       /* no going backward */
 
890
        acc = j->p_ship.s_imp.acc;      /* accelleration for impulse */
 
891
        dcc = j->p_ship.s_imp.dec;      /* decelleration for impulse */
 
892
        fcost = j->p_ship.s_imp.cost * j->p_speed;      /* fuel used for impulse */
 
893
        ecost = j->p_ship.s_imp.etemp * j->p_speed;     /* E-temp for impulse */
 
894
    }
 
895
    if ((j->p_desspeed > maxspeed)      /* if we are too damage to go max */
 
896
    /* && (j->p_damage < 0.9 * j->p_ship.s_maxdamage) */
 
897
        )
 
898
        j->p_desspeed = maxspeed;       /* then set a new desired speed */
 
899
    if ((j->p_flags & PFENG)    /* if E-temped or repairing */
 
900
        &&!(j->p_flags & PFREPAIR))
 
901
        j->p_desspeed = 0;      /* speed drops to 0 */
 
902
    j->p_fuel -= fcost;         /* suck up fuel */
 
903
    j->p_subetemp += ecost;     /* heat the engines */
 
904
    if (allows_docking(j->p_ship)) {    /* if ships can dock to this */
 
905
        for (k = 0; k < j->p_ship.s_numports; k++)      /* go through all ports */
 
906
            if (j->p_port[k] >= 0) {    /* if ship docked there */
 
907
                t = (float) players[j->p_port[k]].p_ship.s_mass /
 
908
                    (float) j->p_ship.s_mass;
 
909
                j->p_fuel -= (int) (t * (float) fcost);
 
910
                j->p_subetemp += (int) (t * (float) ecost);
 
911
            }
 
912
    }
 
913
    while (j->p_subetemp > 1000) {      /* add on the high part of subetemp */
 
914
        j->p_etemp += 1;        /* to etemp */
 
915
        j->p_subetemp -= 1000;
 
916
    }
 
917
 
 
918
    /*
 
919
     * check acceleration, only if we have fuel.
 
920
     * if we need to slow down, do that, but do it if we are
 
921
     * out of fuel as well.
 
922
     */
 
923
    if ( (j->p_desspeed > j->p_speed) && (j->p_fuel > j->p_ship.s_recharge) ) { 
 
924
        j->p_subspeed += acc;   /* add on accelleration */
 
925
    }
 
926
    /*
 
927
     * no fuel?  force him to slow down.
 
928
     */
 
929
    if( j->p_fuel < 0 )
 
930
        j->p_desspeed = 1;
 
931
    if ( j->p_desspeed < j->p_speed ) {/* if we need to go slower */
 
932
        j->p_subspeed -= dcc;   /* decrease our speed */
 
933
    }
 
934
    if (j->p_subspeed / 1000) { /* if fractional part big enough */
 
935
        j->p_speed += j->p_subspeed / 1000;     /* change integer speed */
 
936
        if ((j->p_subspeed < 0 && j->p_speed < j->p_desspeed) ||
 
937
            (j->p_subspeed > 0 && j->p_speed > j->p_desspeed)) {
 
938
            /* went too far, adjust [BDyess] */
 
939
            j->p_speed = j->p_desspeed;
 
940
            j->p_subspeed = 0;
 
941
        }
 
942
        else {
 
943
            j->p_subspeed %= 1000;      /* adjust the fractional part */
 
944
            if (j->p_speed < 0) /* can't go below zero speed */
 
945
                j->p_speed = 0;
 
946
        }
 
947
 
 
948
        if ((!configvals->warpdecel) && j->p_speed > maxspeed)
 
949
            /* can't exceed maxspeed */
 
950
            j->p_speed = maxspeed;
 
951
 
 
952
    }
 
953
 
 
954
    j->p_x += (double) j->p_speed * Cos[j->p_dir] * WARP1;      /* adjust coords */
 
955
    j->p_y += (double) j->p_speed * Sin[j->p_dir] * WARP1;
 
956
    move_player(j->p_no, j->p_x, j->p_y, 1);
 
957
    if( j->p_fuel < 0 )
 
958
        j->p_fuel = 0;
 
959
}
 
960
 
 
961
 
 
962
 
 
963
 
 
964
/*-------------------------------DOTRACTOR-------------------------------*/
 
965
/*  This function handles the tractoring and pressoring for a player.
 
966
There is a long set of conditions that can turn off tractors.  */
 
967
 
 
968
static void 
 
969
dotractor(struct player *j)     /* the player to do */
 
970
{
 
971
    float   cosTheta, sinTheta; /* Cos and Sin from me to him */
 
972
    int     halfforce;          /* Half force of tractor */
 
973
    float   dist;               /* for finding distance */
 
974
    struct player *victim;
 
975
 
 
976
    if (j->p_flags & PFTRACT) { /* tractor beam on? */
 
977
        victim = &players[j->p_tractor];
 
978
        if ((isAlive(victim))
 
979
            && ((j->p_fuel > j->p_ship.s_tractcost) && !(j->p_flags & PFENG))
 
980
            && ((dist = ihypot(j->p_x - victim->p_x, j->p_y - victim->p_y))
 
981
                < (TRACTDIST) * j->p_ship.s_tractrng)
 
982
            && (!(j->p_flags & (PFORBIT | PFDOCK)))
 
983
             /* && (!(victim->p_flags & PFDOCK)) */ ) {
 
984
 
 
985
            if (victim->p_flags & PFORBIT) {    /* pullplayer out of */
 
986
                victim->p_flags &= ~PFORBIT;    /* orbit */
 
987
            }
 
988
            else if (victim->p_flags & PFDOCK) {
 
989
                /* ooOooo, damage the base */
 
990
                struct player *base = &players[victim->p_docked];
 
991
                int     port_num = victim->p_port[0];
 
992
                int     flags;
 
993
 
 
994
                undock_player(victim);
 
995
 
 
996
                /* we need a better reason than KSHIP */
 
997
                flags = victim->p_flags;
 
998
                victim->p_flags &= ~PFSHIELD;   /* inflict damage on hull */
 
999
                inflict_damage(j, (struct player *) 0, victim, DOCKDAMAGE, KSHIP);
 
1000
                victim->p_flags = flags;
 
1001
 
 
1002
                flags = base->p_flags;
 
1003
                base->p_flags &= ~PFSHIELD;     /* inflict damage on hull */
 
1004
                inflict_damage(j, (struct player *) 0, base, DOCKDAMAGE, KSHIP);
 
1005
                base->p_flags = flags;
 
1006
                base->p_port[port_num] = PDAMAGE;       /* disable that docking
 
1007
                                                           port */
 
1008
            }
 
1009
            j->p_fuel -= j->p_ship.s_tractcost; /* take fuel for tractors */
 
1010
            j->p_subetemp += j->p_ship.s_tractetemp;    /* heat engines up */
 
1011
            cosTheta = victim->p_x - j->p_x;
 
1012
            sinTheta = victim->p_y - j->p_y;
 
1013
            if (dist == 0)      /* like groos in the dark */
 
1014
                dist = 1;       /* avoid the divide by zero */
 
1015
            cosTheta /= dist;   /* normalize sin and cos */
 
1016
            sinTheta /= dist;
 
1017
            halfforce = (WARP1 * j->p_ship.s_tractstr);
 
1018
            if (j->p_flags & PFPRESS)   /* if pressors being */
 
1019
                halfforce = -halfforce; /* used */
 
1020
            /* move the players */
 
1021
 
 
1022
            j->p_x += cosTheta * halfforce / (j->p_ship.s_mass);
 
1023
            j->p_y += sinTheta * halfforce / (j->p_ship.s_mass);
 
1024
            move_player(j->p_no, j->p_x, j->p_y, 1);
 
1025
            victim->p_x -= cosTheta * halfforce / (victim->p_ship.s_mass);
 
1026
            victim->p_y -= sinTheta * halfforce / (victim->p_ship.s_mass);
 
1027
            move_player(j->p_tractor, victim->p_x, victim->p_y, 1);
 
1028
        }
 
1029
        else                    /* else if conditions not met */
 
1030
            j->p_flags &= ~(PFTRACT | PFPRESS); /* for tractor turn off */
 
1031
    }
 
1032
}
 
1033
 
 
1034
/*-----------------------------------------------------------------------*/
 
1035
 
 
1036
 
 
1037
 
 
1038
 
 
1039
 
 
1040
 
 
1041
 
 
1042
 
 
1043
/*------------------------------VISIBLE FUNCTIONS-------------------------*/
 
1044
 
 
1045
/*----------------------------------LOSERSTATS----------------------------*/
 
1046
/*  This function is called when a player is killed and his losses need to
 
1047
be incremented.  */
 
1048
 
 
1049
void 
 
1050
loserstats(int pl)              /* the dead player's number */
 
1051
{
 
1052
    struct player *dude;        /* to point to player */
 
1053
 
 
1054
    if (!status->tourn &&
 
1055
        (configvals->robot_stats && !(players[pl].p_flags & PFROBOT)))
 
1056
      return;
 
1057
 
 
1058
    dude = &players[pl];        /* get pointer to player's structure */
 
1059
    if (dude->p_ship.s_type == STARBASE) {      /* if ship was a SB */
 
1060
        dude->p_stats.st_sblosses++;    /* then inc starbase losses */
 
1061
        status->sblosses++;     /* inc global stats */
 
1062
    }
 
1063
    if (dude->p_ship.s_type == WARBASE) {       /* if ship was a WB */
 
1064
        dude->p_stats.st_wblosses++;    /* then inc warbase losses */
 
1065
        status->wblosses++;     /* inc global stats */
 
1066
    }
 
1067
    else {                      /* else if normal ship */
 
1068
        dude->p_stats.st_tlosses++;     /* inc t-mode losses */
 
1069
        status->losses++;       /* inc games t-mode losses */
 
1070
    }
 
1071
}
 
1072
 
 
1073
 
 
1074
 
 
1075
 
 
1076
/*--------------------------------KILLERSTATS-----------------------------*/
 
1077
/*  This function is called when a player kills another player and his
 
1078
kills need to be increased.  This function will add partial kills if the
 
1079
victim was carrying armies.  */
 
1080
 
 
1081
void 
 
1082
killerstats(int pl, struct player *victim)
 
1083
{
 
1084
    struct player *dude;        /* to point to killer's player struct */
 
1085
 
 
1086
    if (!status->tourn && 
 
1087
        (configvals->robot_stats && !(players[pl].p_flags & PFROBOT)))
 
1088
        return;
 
1089
 
 
1090
    dude = &players[pl];        /* get killer's player struct */
 
1091
    if (dude->p_ship.s_type == STARBASE) {      /* if player in SB then */
 
1092
        dude->p_stats.st_sbkills++;     /* inc SB kills */
 
1093
        status->sbkills++;      /* inc global SB kills */
 
1094
    }
 
1095
    else if (dude->p_ship.s_type == WARBASE) {  /* else if in warbase */
 
1096
        dude->p_stats.st_wbkills++;     /* inc warbase kills */
 
1097
        status->wbkills++;      /* inc global WB kills */
 
1098
    }
 
1099
    else {                      /* else in normal ship */
 
1100
        dude->p_stats.st_tkills++;      /* inc t-mode kills */
 
1101
        status->kills++;        /* inc global kills */
 
1102
    }
 
1103
    dude->p_stats.st_tdooshes += victim->p_armies;
 
1104
    dude->p_dooshes += victim->p_armies;
 
1105
    status->dooshes += victim->p_armies;        /* add to global dooshes */
 
1106
    dude->p_stats.st_di += 0.02 * 5.0 * (float) victim->p_armies;
 
1107
    if (victim->p_ship.s_type == STARBASE)
 
1108
        dude->p_stats.st_di += 3.0;
 
1109
    if (victim->p_ship.s_type == WARBASE)
 
1110
        dude->p_stats.st_di += 1.5;
 
1111
    if (victim->p_ship.s_type == PATROL)
 
1112
        dude->p_stats.st_di += 0.03;
 
1113
    else
 
1114
        dude->p_stats.st_di += 0.04;
 
1115
    /* give robots additional DI for kills, since it's all they ever do ;)*/
 
1116
    if (dude->p_flags & PFROBOT && configvals->robot_stats)
 
1117
        dude->p_stats.st_di += 0.05;
 
1118
}
 
1119
 
 
1120
 
 
1121
 
 
1122
 
 
1123
/*------------------------------CHECKMAXKILLS-------------------------------*/
 
1124
/* This function checks to see if a player has exceeded his max kills and if
 
1125
he has, it records the new max kills.  */
 
1126
 
 
1127
void 
 
1128
checkmaxkills(int pl)           /* # of player to check */
 
1129
{
 
1130
    struct stats *stats;        /* to point to player's struct */
 
1131
    struct player *dude;        /* to point to his stats struct */
 
1132
 
 
1133
    if (!status->tourn && 
 
1134
        (configvals->robot_stats && !(players[pl].p_flags & PFROBOT)))
 
1135
        return;
 
1136
    dude = &(players[pl]);      /* get player's player struct */
 
1137
    stats = &(dude->p_stats);   /* get player's stat struct */
 
1138
    if (dude->p_ship.s_type == STARBASE) {      /* if in starbase then */
 
1139
        if (stats->st_sbmaxkills < dude->p_kills)       /* check max SB kills */
 
1140
            stats->st_sbmaxkills = dude->p_kills;       /* set if new max kills */
 
1141
    }
 
1142
    else if (dude->p_ship.s_type == WARBASE) {  /* warbase max kills */
 
1143
        if (stats->st_wbmaxkills < dude->p_kills)       /* check max WB kills */
 
1144
            stats->st_wbmaxkills = dude->p_kills;       /* set if new max kills */
 
1145
    }
 
1146
    else if (stats->st_tmaxkills < dude->p_kills) {     /* else normal ship */
 
1147
        stats->st_tmaxkills = dude->p_kills;    /* set if new max kills */
 
1148
    }
 
1149
}
 
1150
 
 
1151
 
 
1152
 
 
1153
 
 
1154
/*----------------------------------BEAM----------------------------------*/
 
1155
/*  This function goes through all the players and if any are beaming up
 
1156
or down, the beaming is done here.  */
 
1157
 
 
1158
void 
 
1159
beam(void)
 
1160
{
 
1161
    register int i;             /* looping variable */
 
1162
    register struct player *j;
 
1163
 
 
1164
    for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
 
1165
        if ((j->p_status != PALIVE) || !(j->p_flags & (PFORBIT | PFDOCK)))
 
1166
            continue;
 
1167
        if (j->p_flags & PFBEAMUP) {    /* if beaming up */
 
1168
            beammeupscotty(j);  /* do the beamup */
 
1169
        }
 
1170
        else if (j->p_flags & PFBEAMDOWN) {     /* else if beaming down */
 
1171
            beamdown(j);        /* do the beam down */
 
1172
        }
 
1173
    }
 
1174
}
 
1175
 
 
1176
 
 
1177
 
 
1178
 
 
1179
/*---------------------------------UDCLOAK--------------------------------*/
 
1180
/*  This function incs/decs the cloakphase for the players.  */
 
1181
 
 
1182
void 
 
1183
udcloak(void)
 
1184
{
 
1185
    register int i;             /* looping var */
 
1186
 
 
1187
    for (i = 0; i < MAXPLAYER; i++) {   /* go through all players */
 
1188
        if (isAlive(&players[i]))       /* if player is alive */
 
1189
        {
 
1190
            if ((players[i].p_flags & PFCLOAK)  /* if cloaking */
 
1191
                &&(players[i].p_cloakphase < (CLOAK_PHASES - 1)))
 
1192
                players[i].p_cloakphase++;      /* on to next pahse */
 
1193
            else if (!(players[i].p_flags & PFCLOAK)    /* if uncloaking */
 
1194
                     &&(players[i].p_cloakphase > 0))
 
1195
                players[i].p_cloakphase--;      /* on to next phase */
 
1196
         }
 
1197
    }
 
1198
}
 
1199
 
 
1200
 
 
1201
 
 
1202
/*-------------------------------UDPLAYERS---------------------------------*/
 
1203
/*  This function updates all the players.  It handles most of the functions
 
1204
dealing with the player's ship.  If there are no players in the game, then
 
1205
this function will set the dietime variable that the move function in the
 
1206
daemon will use to shut down the deamon.  */
 
1207
 
 
1208
void 
 
1209
udplayers(void)
 
1210
{
 
1211
    register int i;             /* looping vars */
 
1212
    register struct player *j;  /* to point to players */
 
1213
    int     nplayers;           /* number of open slots */
 
1214
 
 
1215
    nplayers = 0;               /* zero the player count */
 
1216
    for (i = status->active = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
 
1217
        switch (j->p_status) {  /* test the player's status */
 
1218
        case POUTFIT:           /* player being ghostbusted */
 
1219
            if (++(j->p_ghostbuster) > OUTFITTIME) {    /* if time ran out */
 
1220
                saveplayer(j);  /* then save the player */
 
1221
                j->p_status = PFREE;    /* free up the player slot */
 
1222
                move_player(j->p_no, -1, -1, 1);
 
1223
            }
 
1224
            break;              /* on to next player */
 
1225
        case PFREE:             /* if slot free then */
 
1226
            nplayers++;         /* inc players not here */
 
1227
            j->p_ghostbuster = 0;       /* so not to bust new players */
 
1228
            break;              /* on to next player */
 
1229
        case PDEAD:             /* if player dead */
 
1230
            if (--j->p_explode <= 0) {  /* dec exp timer, if below zero then */
 
1231
                saveplayer(j);  /* player is busted, save him */
 
1232
                j->p_status = POUTFIT;  /* change status to busted */
 
1233
            }
 
1234
            break;              /* on to next player */
 
1235
        case PEXPLODE:          /* if player exploding */
 
1236
            doshipexplode(j);   /* do the explosion stuff */
 
1237
            /* no break, so this will fall through */
 
1238
            /* and the explosion will move */
 
1239
        case PALIVE:            /* the player is alive */
 
1240
            if ((j->p_flags & PFORBIT) && !(j->p_flags & PFDOCK))
 
1241
                doorbit(j);     /* if player orbiting him */
 
1242
            else if (!(j->p_flags & PFDOCK))
 
1243
                domove(j);      /* move player through space */
 
1244
 
 
1245
            dobounce(j);        /* bounce off of walls */
 
1246
            if (j->p_status == PEXPLODE || j->p_status == PDEAD)
 
1247
                break;          /* player dead or exploding then stop */
 
1248
            if (status->tourn && j->p_status == PALIVE)
 
1249
                switch (j->p_ship.s_type) {
 
1250
                case STARBASE:
 
1251
                    j->p_stats.st_sbticks++;    /* inc SB ticks */
 
1252
                    status->sbtime++;   /* inc global SB time */
 
1253
                    break;
 
1254
                case WARBASE:
 
1255
                    j->p_stats.st_wbticks++;    /* inc WB ticks */
 
1256
                    status->wbtime++;   /* inc global WB time */
 
1257
                    break;
 
1258
                case JUMPSHIP:
 
1259
                    j->p_stats.st_jsticks++;    /* inc JS ticks */
 
1260
                    status->jstime++;   /* inc global JS time */
 
1261
                    break;
 
1262
                default:
 
1263
                    j->p_stats.st_tticks++;     /* inc t-mode ticks */
 
1264
                    status->timeprod++; /* and global t-mode ticks */
 
1265
                    break;
 
1266
                }
 
1267
            else if (j->p_flags & PFROBOT && configvals->robot_stats)
 
1268
                switch (j->p_ship.s_type) {
 
1269
                case STARBASE:
 
1270
                    j->p_stats.st_sbticks++;    /* inc SB ticks */
 
1271
                    break;
 
1272
                case WARBASE:
 
1273
                    j->p_stats.st_wbticks++;    /* inc WB ticks */
 
1274
                    break;
 
1275
                case JUMPSHIP:
 
1276
                    j->p_stats.st_jsticks++;    /* inc JS ticks */
 
1277
                    break;
 
1278
                default:
 
1279
                    j->p_stats.st_tticks++;     /* inc t-mode ticks */
 
1280
                    break;
 
1281
                }
 
1282
 
 
1283
            if (j->p_jsdock > 0)/* inc js dock time */
 
1284
                j->p_jsdock = (++j->p_jsdock < 1200) ? j->p_jsdock : 0;
 
1285
            if (++(j->p_ghostbuster) > GHOSTTIME) {     /* if ghost timer */
 
1286
                cause_kaboom(j);/* ghost bust him--explode */
 
1287
                ghostmess(j);   /* go do the ghost shit */
 
1288
                saveplayer(j);  /* save the sorry bastard */
 
1289
                j->p_whydead = KGHOST;  /* killed by ghostbusters */
 
1290
                j->p_whodead = i;       /* killed by himself */
 
1291
            }
 
1292
            status->active += (1 << i); /* ??????????? */
 
1293
            j->p_updates++;     /* inc time alive */
 
1294
            doresources(j);     /* go do various ship things */
 
1295
            dotractor(j);       /* do the tractors */
 
1296
 
 
1297
            enforce_dock_position(j);
 
1298
            doalert(j);         /* check alert status */
 
1299
            break;
 
1300
 
 
1301
        case POBSERVE:
 
1302
            if (++(j->p_ghostbuster) > GHOSTTIME) {     /* if ghost timer */
 
1303
                saveplayer(j);  /* save the sorry bastard */
 
1304
                j->p_status = PFREE;
 
1305
                move_player(j->p_no, -1, -1, 1);
 
1306
            }
 
1307
            if (j->p_flags & PFPLOCK) { /* watching a player */
 
1308
                struct player *watched = &players[j->p_playerl];
 
1309
                if (watched->p_team == j->p_team) {
 
1310
                    j->p_x = watched->p_x;
 
1311
                    j->p_y = watched->p_y;
 
1312
                }
 
1313
                else {
 
1314
                    j->p_flags &= ~(PFPLOCK | PFPLLOCK);
 
1315
                }
 
1316
            }
 
1317
            else if (j->p_flags & PFPLLOCK) {   /* watching a planet */
 
1318
                struct planet *watched = &planets[j->p_planet];
 
1319
                if (watched->pl_owner == j->p_team) {
 
1320
                    j->p_x = watched->pl_x;
 
1321
                    j->p_y = watched->pl_y;
 
1322
                }
 
1323
                else {
 
1324
                    j->p_flags &= ~(PFPLOCK | PFPLLOCK);
 
1325
                }
 
1326
            }
 
1327
            else {
 
1328
                j->p_x = -10000;
 
1329
                j->p_y = -10000;/* out of the action... */
 
1330
            }
 
1331
            break;
 
1332
 
 
1333
        default:
 
1334
            if (++(j->p_ghostbuster) > GHOSTTIME) {     /* if ghost timer */
 
1335
                ghostmess(j);   /* go do the ghost shit */
 
1336
                saveplayer(j);  /* save the sorry bastard */
 
1337
                j->p_status = PFREE;
 
1338
                move_player(j->p_no, -1, -1, 1);
 
1339
            }
 
1340
            break;
 
1341
        }                       /* end of switch */
 
1342
    }                           /* end of for loop through players */
 
1343
    if (nplayers == MAXPLAYER) {/* if no players playing */
 
1344
        if (dietime == -1)      /* if daemon die timer not running */
 
1345
            dietime = ticks + 600 / PLAYERFUSE; /* set it for one minute */
 
1346
        if(status2->starttourn)         /* no players, so reset to make it a fresh */
 
1347
            status2->newgalaxy = 1;     /*   galaxy */
 
1348
    }
 
1349
    else                        /* else stop daemon die timer */
 
1350
        dietime = -1;
 
1351
 
 
1352
    if (status2->league && status->tourn) {
 
1353
        int     leaguecount[2]; /* used to bench excess players */
 
1354
 
 
1355
        leaguecount[0] = leaguecount[1] = 0;
 
1356
 
 
1357
        /* count up how many live players on each team */
 
1358
        for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
 
1359
            if (players[i].p_status == PALIVE) {
 
1360
                int     which = (j->p_team == idx_to_mask(status2->away.index));
 
1361
                leaguecount[which]++;
 
1362
            }
 
1363
        }
 
1364
 
 
1365
        if (leaguecount[0] >= configvals->playersperteam ||
 
1366
            leaguecount[1] >= configvals->playersperteam) {
 
1367
            /*
 
1368
               if we're full of live players then all non-live players must
 
1369
               sit on the bench
 
1370
            */
 
1371
            for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
 
1372
                int     which = (j->p_team == idx_to_mask(status2->away.index));
 
1373
                if (j->p_status != PALIVE && j->p_status != POBSERVE
 
1374
                    && leaguecount[which] >= configvals->playersperteam) {
 
1375
                    j->p_observer = 1;
 
1376
                }
 
1377
            }
 
1378
        }
 
1379
 
 
1380
        leaguecount[0] = leaguecount[1] = 0;
 
1381
 
 
1382
        /* count up how many playing players on each team */
 
1383
        for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
 
1384
            if (players[i].p_status != PFREE &&
 
1385
                players[i].p_status != POBSERVE) {
 
1386
                int     which = (j->p_team == idx_to_mask(status2->away.index));
 
1387
                leaguecount[which]++;
 
1388
            }
 
1389
        }
 
1390
 
 
1391
        if (leaguecount[0] < configvals->playersperteam ||
 
1392
            leaguecount[1] < configvals->playersperteam) {
 
1393
            /*
 
1394
               if a team is short, let an observer who doesn't want to
 
1395
               observe come in
 
1396
            */
 
1397
            for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
 
1398
                int     which = (j->p_team == idx_to_mask(status2->away.index));
 
1399
                if (j->p_status == POBSERVE
 
1400
                    && leaguecount[which] < configvals->playersperteam
 
1401
                    && j->p_observer == 0) {
 
1402
                    j->p_whydead = KPROVIDENCE;
 
1403
                    j->p_whodead = -1;
 
1404
                    j->p_status = POUTFIT;
 
1405
                    leaguecount[which]++;
 
1406
                }
 
1407
            }
 
1408
        }
 
1409
 
 
1410
        /* check for refits and unexpected deaths */
 
1411
        scan_for_unexpected_tourny_events();
 
1412
    }
 
1413
}
 
1414
 
 
1415
/*------------------------------------------------------------------------*/
 
1416
 
 
1417
 
 
1418
 
 
1419
 
 
1420
 
 
1421
/*----------END OF FILE--------*/