comparison src/planets.c @ 6:8c6d5731234d

First entry of Paradise Server 2.9 patch 10 Beta
author darius
date Sat, 06 Dec 1997 04:37:04 +0000
parents
children
comparison
equal deleted inserted replaced
5:054275999194 6:8c6d5731234d
1 /*--------------------------------------------------------------------------
2 NETREK II -- Paradise
3
4 Permission to use, copy, modify, and distribute this software and its
5 documentation, or any derivative works thereof, for any NON-COMMERCIAL
6 purpose and without fee is hereby granted, provided that this copyright
7 notice appear in all copies. No representations are made about the
8 suitability of this software for any purpose. This software is provided
9 "as is" without express or implied warranty.
10
11 Xtrek Copyright 1986 Chris Guthrie
12 Netrek (Xtrek II) Copyright 1989 Kevin P. Smith
13 Scott Silvey
14 Paradise II (Netrek II) Copyright 1993 Larry Denys
15 Kurt Olsen
16 Brandon Gillespie
17 --------------------------------------------------------------------------*/
18
19
20 #define PLANETS 1
21 #define GRID 0 /* for space grid */
22
23 #include "config.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <math.h>
28 #include <setjmp.h>
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <unistd.h>
32
33 #include "struct.h"
34 #include "data.h"
35 #include "daemonII.h"
36 #include "planets.h"
37 #include "misc.h"
38 #include "conquer.h"
39 #include "player.h"
40 #include "grid.h"
41 #include "shmem.h"
42 #include "terrain.h"
43
44
45 /* define this if you want the experimental dragging-into-star-counts mod */
46 #define GIVESTARKILLS
47
48 #define friendly(fred, bart) \
49 (!(fred->p_team & (bart->p_swar|bart->p_hostile)) && \
50 !(bart->p_team & (fred->p_swar|fred->p_hostile)))
51
52
53 /* defines dealing with growth timers */
54 #define PLGFUEL configvals->plgrow.fuel /* time for growth of fuel
55 * depot */
56 #define PLGAGRI configvals->plgrow.agri /* time for growth of agri */
57 #define PLGREPAIR configvals->plgrow.repair /* time for growth of
58 * repair */
59 #define PLGSHIP configvals->plgrow.shipyard /* time for growth of
60 * shipyard */
61
62 /* other defines */
63 #define UCVISIBLE 40000 /* dist for uncloaked visibility */
64 #define CVISMIN 12000 /* cloakers always visible distance */
65 #define CVISSPEED 2000 /* cloak dist added per warp point */
66 #define CVISIBLE 25000 /* dist for cloaked visibility */
67 #define PLFIREDIST 1500 /* distance planets fire at players */
68 #define PLVISDIST 5000 /* dist planets sense enemy players */
69 #define REVOLT 200 /* chance out of 1000 of revolt start */
70 #define STARTREV 8 /* for revolt timer */
71 /*-------------------------------------------------------------------------*/
72
73
74
75
76
77
78 /*-----------------------------MODULE VARIABLES----------------------------*/
79
80 /* the list of all possible planet names */
81 char *pnames[] =
82 {
83 /* Federation planets */
84 "Rigel", "Canopus", "Beta Crucis", "Organia", "Deneb",
85 "Ceti Alpha V", "Altair", "Vega", "Alpha Centauri",
86 /* Romulan worlds */
87 "Eridani", "Aldeberan", "Regulus", "Capella", "Tauri",
88 "Draconis", "Sirius", "Indi", "Hydrae",
89 /* Klingon worlds */
90 "Pleiades V", "Andromeda", "Lalande", "Pollux", "Lyrae",
91 "Scorpii", "Mira", "Cygni", "Castor",
92 /* Orion worlds */
93 "Cassiopia", "El Nath", "Spica", "Procyon", "Polaris",
94 "Arcturus", "Ursae Majoris", "Herculis", "Antares",
95
96 /* new worlds */
97 "Planet 10", "Bezier", "Sequent", "Ophiuchi", "Lacaille",
98 "Luyten", "Pavonis", "Wolf 424", "Ross 882", "Cephei",
99 "Kruger", "Groombridge", "Maanen's Star", "Heinlein",
100 "Pixel", "Lazarus", "Mycroft", "Asimov", "Varley",
101 "Clarke's Star", "Ren", "Stimpy", "Foo", "Jolt Cola",
102 "Kelly Bundy", "Tyrell", "Roy", "Deckard", "Vangelis",
103 "Orpheus", "Xanth", "Tatooine", "Ludicrous", "Ogg",
104 "Scum", "Twink", "Chiapucci", "Bugno", "Hampsten", "Fignon",
105 "Paradise", "Azriel", "Gargamel", "Smurf Village",
106 "Praxis", "Acherner", "Arrakis", "Caladan", "Giedi Prime",
107 "Clue", "Paulina", "Sith", "Salusa", "Ahrain", "Cerranos",
108 "Darkurthe", "Dagobah", "Phaze", "Chatsubu", "Lemond",
109 "Bronco", "Vulcan", "Eden", "Klein", "Merckx", "Tarot",
110 "Mottet", "Roche", "Doorstop", "Shaedron", "Fondriest",
111
112 /* Bob's fave worlds */
113 "Wayne's World", "DanjerHaus", "Anvil", /* B-52s */ "Claire",
114 "Planet Reebok", "Sony Corp.", "SEGA!", "McWorld",
115 "Tokyo", "New York", "D.C.", "Atlanta", /* places I've never been */
116 /* Tony */ "Levin",
117 "Planet Woogie", "Nancy", "Wilson", /* real people */
118 "Beavis", "Butthead",
119 "Memolo", /* Matt Memolo was murdered in Miami in July
120 * of '93. He was a really swell guy. "...he
121 * would go far out of his way to give you
122 * the shirt off his back." - ajc */
123 /* names from the T.V. shows */
124 "New Berlin",
125 /*
126 * "Bejor", "Cardassia" I'm not including these till I can spell them - RF
127 */
128
129 /* Mike's fave worlds */
130 "Melmac", "Order", "Yosemite", "New Chicago", "Ceptus", "Ork",
131 "Levi 501", "Toughskin", "Wonka",
132
133 /* book names */
134 "Terminus", "Magrathea", "Trantor", "Synnax", "Coruscant",
135
136 /* Moons, names, etc. */
137 "Io ", "Titan", "Europa", "Ganymede", "Charon",
138 "Tholia", "Gor", "Kzin", "Aerth",
139 "Proxima", "Cellust", "Calamar", "Icarus",
140 "New Prague",
141
142 /* How about the solar system? */
143 "Mercury", "Venus", "Mars", "Jupiter", "Saturn", "Neptune",
144 "Uranus", "Pluto", /* are Neptune and Uranus in order? */
145
146 #if 0
147 /* Player's names */
148 "Claypigeon", "Maxout", "Fungus", "Lynx",
149 "Bubbles", "KnightRaven", "Bolo", "Vladimir",
150 "Gajah Mada", "Trippix", "Shrew", "Bob Dobbs", "Wibble",
151 "Rogue"
152 #endif
153 };
154
155 #define MAXNAMES (sizeof(pnames)/sizeof(char *)) /* # of planet names */
156
157 char *homenames[] = /* names of the race's home worlds */
158 {
159 " ", "Earth", "Romulus", " ", "Klingus", " ", " ", " ",
160 "Orion"
161 };
162
163
164 /*
165 * This table is used to turn the four bits of resources flags into a three
166 * bit number. The shipyard and the repair are ORed together. All the non
167 * resource bits need to be masked off with PLRESMASK before this table is
168 * used
169 */
170 int restores[16] = {0, 1, 2, 3, 4, 5, 6, 7, 1, 1, 3, 3, 5, 5, 7, 7};
171
172
173 /*
174 * This is a matrix that determines the chance a planet has of popping. The
175 * chance is expressed as a chance out of 100. The matrix is accessed with
176 * the planet's atmosphere type and the resource bits after they have been
177 * converted to 3 bits with the table above.
178 */
179 int popchance[4][8] = {
180 /*
181 * 000 00Z 0f0 0fZ a00 a0Z af0 afZ--the resources flags,
182 * Z=r|s
183 */
184 {2, 3, 2, 2, 5, 7, 4, 8}, /* poison */
185 {3, 5, 2, 4, 9, 11, 7, 12}, /* atmos #3 */
186 {5, 7, 4, 6, 12, 14, 10, 15}, /* atmos #2 */
187 {8, 12, 7, 10, 20, 24, 18, 23}/* atmos #1 */
188 };
189
190
191 /*
192 * This is a matrix that determines the multiplier for popping. When popping
193 * the armies on a planet will be multiplied by this multiplier to get the
194 * number of extra armies that grow. A negative number indicates negative
195 * growth.
196 */
197 float popmult[4][8] = {
198 /* 000 00Z 0f0 0fZ a00 a0Z af0 afZ */
199 {-0.08, 0.00, -0.10, -0.03, 0.00, 0.05, -0.05, 0.05}, /* poison */
200 {0.03, 0.05, 0.02, 0.04, 0.06, 0.07, 0.06, 0.07}, /* atmos #3 */
201 {0.05, 0.07, 0.05, 0.06, 0.10, 0.11, 0.08, 0.10}, /* atmos #2 */
202 {0.09, 0.12, 0.08, 0.10, 0.17, 0.19, 0.15, 0.18} /* atmos #1 */
203 };
204
205
206 /*
207 * This is a matrix that determines the maximum army capacity of a planet.
208 * Once this capacity is reached, no other armies can grow there.
209 */
210 float popcap[4][8] = {
211 /*
212 * 000 00Z 0f0 0fZ a00 a0Z af0 afZ--the resources flags,
213 * Z=r|s
214 */
215 {5, 10, 7, 10, 15, 15, 10, 18}, /* poison */
216 {9, 14, 11, 14, 20, 20, 14, 22}, /* atmos #3 */
217 {12, 18, 15, 18, 25, 25, 19, 27}, /* atmos #2 */
218 {15, 22, 18, 25, 40, 35, 27, 40} /* atmos #1 */
219 };
220
221 /*-------------------------------------------------------------------------*/
222
223
224
225
226
227
228
229
230 #ifdef LEAGUE_SUPPORT
231 extern void tlog_res();
232 extern void tlog_bomb();
233 extern void tlog_bres();
234 extern void tlog_plankill();
235 extern void tlog_revolt();
236 extern void tlog_pop();
237 #else
238 #define tlog_res(a,b)
239 #define tlog_bomb(a,b,c)
240 #define tlog_bres(a,b,c)
241 #define tlog_plankill(a,b,c)
242 #define tlog_revolt(a)
243 #define tlog_pop(a,b)
244 #endif
245 extern void scout_planet();
246 extern int inflict_damage();
247 extern void killmess();
248 extern int enemy_admiral();
249 extern off_t lseek();
250 extern int write();
251
252 /*------------------------------INTERNAL FUNCTIONS-------------------------*/
253
254 void fill_planets();
255
256
257 #ifndef NO_QSORT
258 /* used by the qsort() in sortnames() below */
259 static int
260 comp_pl_name(a, b)
261 void *a, *b;
262 {
263 return strcasecmp(((struct planet *) a)->pl_name,
264 ((struct planet *) b)->pl_name);
265 }
266 #endif
267
268 /*--------------------------------SORTNAMES---------------------------------*/
269 /*
270 * This function sorts the planet into a alphabeticly increasing list. It
271 * operates on the global planets structure. This uses a simple bubble sort
272 * because I was too lazy to write anything more sophisticated.
273 */
274
275 /*
276 * Bubble sorts suck. Let's use the qsort library function instead, if
277 * available (HK)
278 */
279
280 void
281 sortnames()
282 {
283 #ifdef NO_QSORT
284 struct planet ptemp; /* temporary space to hold planet */
285 int exchange; /* flag for exchange made in pass */
286 int i; /* looping var */
287 int t; /* temp var */
288
289 exchange = 1; /* no exchanges done yet */
290 while (exchange)
291 { /* do until no exchanges */
292 exchange = 0; /* no exchanges for this pass yet */
293 for (i = 0; i < NUMPLANETS - 1; i++)
294 { /* go through list */
295 if (strcmp(planets[i].pl_name, planets[i + 1].pl_name) > 0)
296 {
297 t = planets[i].pl_no; /* exchange planet numbers */
298 planets[i].pl_no = planets[i + 1].pl_no;
299 planets[i + 1].pl_no = t;
300 memcpy(&ptemp, &(planets[i]), sizeof(struct planet));
301 memcpy(&(planets[i]), &(planets[i + 1]), sizeof(struct planet));
302 memcpy(&(planets[i + 1]), &ptemp, sizeof(struct planet));
303 exchange++; /* we made an exchange this pass */
304 }
305 }
306 }
307 #else
308 int i;
309
310 qsort(planets, NUMPLANETS, sizeof(struct planet), comp_pl_name);
311 for (i = 0; i < NUMPLANETS; i++) /* go through the planets */
312 planets[i].pl_no = i; /* and fix their pl_no value */
313 #endif
314 }
315
316
317 /*--------------------------------INITPLANETS-------------------------------*/
318 /*
319 * This function generates the names and initializes the fields in the
320 * planets structure. The planet names need to be sorted afterthe planets
321 * have been placed.
322 */
323
324 void
325 initplanets()
326 {
327 int i, j; /* looping vars */
328 int nused[MAXNAMES]; /* to mark which names are used */
329
330 for (i = 0; i < MAXNAMES; i++)/* go through all possible names */
331 nused[i] = 0; /* mark name is not used yet */
332 for (i = 0; i < NUMPLANETS; i++)
333 {
334 planets[i].pl_no = i; /* set planet number */
335 planets[i].pl_flags = PLPARADISE; /* Paradise planet */
336 planets[i].pl_owner = NOBODY; /* no owner yet */
337 planets[i].pl_x = 0; /* just to intialize x and y */
338 planets[i].pl_y = 0;
339 j = lrand48() % MAXNAMES; /* get a random name */
340 do
341 { /* do until unused name found */
342 j = (j + 1) % MAXNAMES; /* go on to next name in list */
343 } while (nused[j]); /* until unused name found */
344 nused[j] = 1; /* mark name as used */
345 strcpy(planets[i].pl_name, pnames[j]); /* copy into planet struct */
346 planets[i].pl_namelen = strlen(pnames[j]); /* set name's length */
347 #if 1
348 planets[i].pl_hostile = 0; /* planet doesn't hate anyone yet */
349 #else
350 planets[i].pl_torbit = 0; /* no teams orbiting */
351 #endif
352 planets[i].pl_tshiprepair = 0; /* zero the repair growth timer */
353 planets[i].pl_tagri = 0; /* zero the agri growth timer */
354 planets[i].pl_tfuel = 0; /* zero the fuel growth timer */
355 planets[i].pl_armies = 0; /* no armies yet */
356 planets[i].pl_warning = 0; /* no warning being counted down for */
357 planets[i].pl_system = 0; /* not in a system yet */
358 planets[i].pl_hinfo = NOBODY; /* no race has info on planet */
359 for (j = 0; j < MAXTEAM + 1; j++)
360 { /* go through four races */
361 planets[i].pl_tinfo[j].owner = NOBODY; /* do not know who owns it */
362 planets[i].pl_tinfo[j].armies = 0; /* no armies on planet */
363 planets[i].pl_tinfo[j].flags = PLPARADISE; /* know nothing about
364 * flags */
365 planets[i].pl_tinfo[j].timestamp = 0; /* set the timestamp */
366 }
367 planets[i].pl_trevolt = 0; /* revolt timer not counting down */
368 #if GRID
369 planets[i].pl_next = NULL; /* set fields related to space grid */
370 planets[i].pl_previous = NULL;
371 planets[i].pl_gridnum = 0;
372 #endif
373 }
374 }
375
376
377
378
379 /*-------------------------------GROWPLANETS------------------------------*/
380 /*
381 * This function grows resources on planets. It goes through all planets and
382 * updates the growth timers and checks for growth. Independent planets do
383 * not grow. This function also checks to see if any player in a starbase is
384 * orbiting a planet and adjusts the planet's growth rate if so.
385 */
386
387 void
388 growplanets()
389 {
390 int i; /* looping var */
391 struct planet *p; /* to point within planets */
392 int add; /* number to add to timers */
393
394 if (!status->tourn)
395 return;
396
397 if (!configvals->resource_bombing)
398 return;
399
400 for (i = 0; i < MAXPLAYER; i++)
401 { /* go through all players */
402 struct player *py = &players[i]; /* and look for orbiting */
403 if ((py->p_status != PALIVE) || /* starbases */
404 (py->p_ship.s_type != STARBASE) ||
405 !(py->p_flags & PFORBIT))
406 continue;
407 p = &planets[py->p_planet]; /* found one, get planet */
408 p->pl_tfuel += 20; /* give growth rate a boost */
409 p->pl_tagri += 30; /* NOTE: change these if PLG consts */
410 p->pl_tshiprepair += 50; /* change */
411 }
412 p = &planets[0]; /* start with first planet */
413 for (i = 0; i < NUMPLANETS; i++, p++)
414 { /* through all planets */
415 if (p->pl_owner == NOBODY) /* if independent then */
416 continue; /* no growth */
417 add = p->pl_armies / 2; /* rate based on armies */
418 p->pl_tfuel += add; /* add to fuel timer */
419 p->pl_tfuel = (p->pl_tfuel > PLGFUEL) ? PLGFUEL : p->pl_tfuel;
420 if ((!(p->pl_flags & PLFUEL)) /* if no fuel */
421 && (p->pl_flags & PLDILYTH) /* and dilythium deposits */
422 && (p->pl_tfuel >= PLGFUEL))
423 { /* and timer high enough */
424 p->pl_flags |= (PLFUEL | PLREDRAW); /* create fuel depot */
425 p->pl_tinfo[p->pl_owner].flags = p->pl_flags;
426 p->pl_tinfo[p->pl_owner].timestamp = status->clock;
427 tlog_res(p, "FUEL");
428 }
429 p->pl_tagri += add; /* add to agri timer */
430 p->pl_tagri = (p->pl_tagri > PLGAGRI) ? PLGAGRI : p->pl_tagri;
431 if ((!(p->pl_flags & PLAGRI)) /* if no agri on planet */
432 && (p->pl_flags & PLARABLE) /* and arable */
433 && (p->pl_tagri >= PLGAGRI))
434 { /* and timer high enough */
435 p->pl_flags |= (PLAGRI | PLREDRAW); /* create agri planet */
436 p->pl_tinfo[p->pl_owner].flags = p->pl_flags;
437 p->pl_tinfo[p->pl_owner].timestamp = status->clock;
438 tlog_res(p, "AGRI");
439 }
440 p->pl_tshiprepair += add; /* add to ship/repair timer */
441 if ((!(p->pl_flags & PLREPAIR)) /* if not repair */
442 && (p->pl_flags & PLMETAL) /* and metal deposits */
443 && (p->pl_tshiprepair >= PLGREPAIR))
444 { /* and timer high enough */
445 p->pl_flags |= (PLREPAIR | PLREDRAW); /* create repair station */
446 p->pl_tinfo[p->pl_owner].flags = p->pl_flags;
447 p->pl_tinfo[p->pl_owner].timestamp = status->clock;
448 tlog_res(p, "REPAIR");
449 }
450 p->pl_tshiprepair = (p->pl_tshiprepair > PLGSHIP) ? PLGSHIP :
451 p->pl_tshiprepair; /* clamp value to max */
452 if ((!(p->pl_flags & PLSHIPYARD)) /* if not repair */
453 && (p->pl_flags & PLMETAL) /* and metal deposits */
454 && (p->pl_tshiprepair >= PLGSHIP))
455 { /* and timer high enough */
456 p->pl_flags |= (PLSHIPYARD | PLREDRAW); /* create repair station */
457 p->pl_tinfo[p->pl_owner].flags = p->pl_flags;
458 p->pl_tinfo[p->pl_owner].timestamp = status->clock;
459 tlog_res(p, "SHIPYARD");
460 }
461 }
462 }
463
464
465
466
467 /*----------------------------------PVISIBLE------------------------------*/
468 /*
469 * This function goes through the players and checks the other playes to see
470 * if an enemy is close enough to see him. THIS FUNCTION SHOULD EVENTUALLY
471 * USE THE SPACE GRID.
472 */
473
474 void
475 pvisible()
476 {
477 struct player *p; /* to point to a player */
478 int i; /* looping var */
479 int h; /* looping var */
480 struct player *pl2; /* to point to other players */
481 int dx, dy; /* delta coords */
482 int dist; /* to hold distance */
483
484 for (i = 0, p = &players[0]; i < MAXPLAYER; i++, p++)
485 p->p_flags &= ~PFSEEN; /* clear all players' the seen flags */
486 for (i = 0, p = &players[i]; i < MAXPLAYER - 1; i++, p++)
487 {
488 if (p->p_status != PFREE && /* only do if player alive */
489 p->p_status != POBSERVE)
490 { /* observers can't augment team scanning */
491 for (h = i + 1, pl2 = &players[h]; h < MAXPLAYER; h++, pl2++)
492 {
493 if ((pl2->p_status == PFREE) || (pl2->p_status == POBSERVE)
494 || (pl2->p_flags & PFROBOT) /* if not alive or robot or */
495 || (pl2->p_team == p->p_team)) /* same team then continue */
496 continue;
497 dx = ABS(pl2->p_x - p->p_x); /* calc delta coords */
498 dy = ABS(pl2->p_y - p->p_y);
499 if ((dx > UCVISIBLE) || (dy > UCVISIBLE)) /* if obviously too far
500 * away */
501 continue; /* then don't bother further */
502 dist = ihypot(dx, dy);
503 if (dist > UCVISIBLE) /* out of range */
504 continue; /* on to next ship */
505 if ((dist < CVISMIN + CVISSPEED * pl2->p_speed) ||
506 (!(pl2->p_flags & PFCLOAK)))
507 pl2->p_flags |= PFSEEN; /* if close then visible */
508 if ((dist < CVISMIN + CVISSPEED * p->p_speed) ||
509 (!(p->p_flags & PFCLOAK)))
510 p->p_flags |= PFSEEN; /* second player */
511 }
512 }
513 }
514 }
515
516
517
518 void
519 blast_resource(p, l, res, dival)
520 struct player *p;
521 struct planet *l;
522 int res;
523 double dival;
524 {
525 if (status->tourn)
526 {
527 p->p_stats.st_di += dival;
528 p->p_stats.st_tresbomb++;
529 p->p_resbomb++;
530 status->resbomb++;
531 }
532 l->pl_flags &= ~res;
533 l->pl_tinfo[l->pl_owner].flags = l->pl_flags;
534 l->pl_tinfo[l->pl_owner].timestamp = status->clock;
535 l->pl_tinfo[p->p_team].flags = l->pl_flags;
536 l->pl_tinfo[p->p_team].timestamp = status->clock;
537 l->pl_flags |= PLREDRAW; /* slate for redraw */
538 }
539
540 /*-----------------------------------PBOMB---------------------------------*/
541 /*
542 * This function goes through the players and does the bombing if any player
543 * is bombing. This will knock resources off of planets. If a player is
544 * bombing a planet that another team owns, then that team will see the
545 * player by having the PFSEEN flag set.
546 */
547
548 void
549 pbomb()
550 {
551 struct player *p; /* to point to a player */
552 int i; /* looping var */
553 struct planet *l; /* to point to planet being bombed */
554 char buf[90]; /* to sprintf messages into */
555 char buf1[80];
556 int rnd; /* to hold armies to knock off */
557
558 for (i = 0, p = &players[0]; i < MAXPLAYER; i++, p++)
559 { /* go through playrs */
560 if ((p->p_status == PALIVE) /* only do if player is alive */
561 && (p->p_flags & PFORBIT) /* and he is orbiting */
562 && (p->p_flags & PFBOMB))
563 { /* and he is bombing */
564
565 l = &planets[p->p_planet];/* get planet being bombed */
566
567 if ((!((p->p_swar | p->p_hostile) & l->pl_owner))
568 && (l->pl_owner != NOBODY))
569 {
570 /* if he's non-hostile, quit bombing */
571 p->p_flags &= ~PFBOMB;
572 continue;
573 }
574 if ((l->pl_warning <= 0) && (l->pl_owner != NOBODY))
575 { /* warning? */
576 l->pl_warning = 50 / PLFIGHTFUSE; /* reset warning timer */
577 sprintf(buf, "We are being attacked by %s %s who is %d%% damaged.",
578 p->p_name, twoletters(p),
579 (100 * p->p_damage) / (p->p_ship.s_maxdamage));
580 sprintf(buf1, "%-3s->%-3s", l->pl_name, teams[l->pl_owner].shortname);
581 pmessage(buf, l->pl_owner, MTEAM | MBOMB, buf1); /* send message */
582
583 /* CRD feature: shipyard guardians - MAK, 2-Jun-93 */
584 if ((l->pl_flags & PLSHIPYARD) && (!status->tourn))
585 {
586 rescue(l->pl_owner, 0, l->pl_no);
587 }
588 }
589 p->p_swar |= l->pl_owner; /* set player at war w/ owner */
590 rnd = (lrand48() % 50) + p->p_ship.s_bomb; /* pick random number */
591 rnd = (int) ((float) rnd / 33.0 + 0.5); /* calc armies bombed */
592 if (rnd <= 0)
593 continue; /* can't bomb negative armies */
594 if (l->pl_armies > 4)
595 { /* if armies to bomb then */
596 l->pl_armies -= rnd; /* kill off armies */
597 tlog_bomb(l, p, rnd);
598 l->pl_armies = (l->pl_armies < 1) ? 1 : l->pl_armies;
599 l->pl_tinfo[l->pl_owner].armies = l->pl_armies;
600 l->pl_tinfo[l->pl_owner].timestamp = status->clock;
601 l->pl_tinfo[p->p_team].armies = l->pl_armies;
602 l->pl_tinfo[p->p_team].timestamp = status->clock;
603 if (l->pl_armies < 5) /* if planet needs to be redrawn */
604 l->pl_flags |= PLREDRAW; /* schedule planet for redraw */
605 if (l->pl_owner != NOBODY)
606 {
607 credit_armiesbombed(p, rnd, l);
608 }
609 } /* now do the resource bombing */
610 if ((l->pl_armies > 4) ||
611 (!configvals->resource_bombing)) /* no bombing resources if
612 * armies */
613 continue; /* on planet or in bronco-mode */
614 #if defined(AEDILE) || defined(SLOW_BOMB)
615 l->pl_tfuel -= rnd * 5; /* knock fuel timer down */
616 #else
617 l->pl_tfuel -= rnd * 8; /* knock fuel timer down */
618 #endif
619 l->pl_tfuel = (l->pl_tfuel < 0) ? 0 : l->pl_tfuel;
620 if ((l->pl_tfuel == 0) && (l->pl_flags & PLFUEL))
621 {
622 blast_resource(p, l, PLFUEL, 0.10);
623 tlog_bres(l, p, "FUEL");
624 }
625 #if defined(AEDILE) || defined(SLOW_BOMB)
626 l->pl_tagri -= rnd * 4; /* attack the agri timer */
627 #else
628 l->pl_tagri -= rnd * 6; /* attack the agri timer */
629 #endif
630 l->pl_tagri = (l->pl_tagri < 0) ? 0 : l->pl_tagri;
631 if ((l->pl_tagri == 0) && (l->pl_flags & PLAGRI))
632 {
633 blast_resource(p, l, PLAGRI, 0.25);
634 tlog_bres(l, p, "AGRI");
635 }
636 #if defined(AEDILE) || defined(SLOW_BOMB)
637 l->pl_tshiprepair -= rnd * 5; /* knock ship/repr down */
638 #else
639 l->pl_tshiprepair -= rnd * 8; /* knock ship/repr down */
640 #endif
641 l->pl_tshiprepair = (l->pl_tshiprepair < 0) ? 0 :
642 l->pl_tshiprepair;
643 if ((l->pl_tshiprepair < PLGREPAIR) && (l->pl_flags & PLSHIPYARD))
644 {
645 blast_resource(p, l, PLSHIPYARD, 0.10);
646 tlog_bres(l, p, "SHIPYARD");
647 }
648 if ((l->pl_tshiprepair == 0) && (l->pl_flags & PLREPAIR))
649 {
650 blast_resource(p, l, PLREPAIR, 0.20);
651 tlog_bres(l, p, "REPAIR");
652 }
653 }
654 }
655 }
656
657
658
659
660 /*---------------------------------PFIRE-----------------------------------*/
661 /*
662 * This function goes through the planets and sees if any enemy players are
663 * close enough to be fired upon by the planet. It also checks to see if
664 * players are close enough to the planet so that the planet should be
665 * redrawn. Enemy planets will 'see' players that are very close to them.
666 * THIS FUNCTION SHOULD EVENTUALLY USE THE SPACE GRID.
667 */
668
669 void
670 pfire()
671 {
672 struct player *p; /* to point to a player */
673 int i, j; /* looping vars */
674 struct planet *l; /* to point to the planets */
675 int dx, dy; /* to hold delta coords */
676 int dist; /* to hold distance */
677 int dam; /* to hold damage */
678 int boost; /* for warp zones, total boost [BDyess] */
679
680 for (j = 0, p = &players[0]; j < MAXPLAYER; j++, p++)
681 {
682 if (p->p_status != PALIVE)
683 continue;
684 boost = 0; /* default no bonus or penalty [BDyess] */
685 for (i = 0, l = &planets[0]; i < NUMPLANETS; i++, l++)
686 {
687 if ((p->p_team == l->pl_owner) && (PL_TYPE(*l) != PLSTAR)
688 && !configvals->warpzone)
689 continue; /* no, then continue */
690 dx = ABS(l->pl_x - p->p_x); /* calc delta coorda between */
691 dy = ABS(l->pl_y - p->p_y); /* planet and player */
692 dist = ihypot(dx, dy);
693
694 if (dist < configvals->warpzone)
695 {
696 /* within warp boost/block range [BDyess] */
697 if (p->p_team == l->pl_owner)
698 boost += configvals->warpzone - dist;
699 else if (l->pl_owner != NOBODY &&
700 ((p->p_swar | p->p_hostile) & l->pl_owner))
701 boost -= configvals->warpzone - dist;
702 }
703
704 if (dx < 6 * PLFIREDIST && dy < 6 * PLFIREDIST) /* redraw planet */
705 l->pl_flags |= PLREDRAW;/* if player is very close */
706
707 if (dist <= p->p_ship.s_scanrange)
708 { /* check for scanners */
709 scout_planet(p->p_no, l->pl_no);
710 #if 0
711 handled in scout_planet now.
712 l->pl_hinfo |= p->p_team;
713 l->pl_tinfo[p->p_team].armies = l->pl_armies;
714 l->pl_tinfo[p->p_team].flags = l->pl_flags;
715 l->pl_tinfo[p->p_team].owner = l->pl_owner;
716 l->pl_tinfo[p->p_team].timestamp = status->clock;
717 #endif
718 }
719
720 if (dist > PLVISDIST)
721 continue;
722 if ((dist < PLVISDIST) && (l->pl_owner != NOBODY) /* enemy planet */
723 && ((p->p_swar | p->p_hostile) & l->pl_owner)) /* see players */
724 p->p_flags |= PFSEEN; /* let team see enemy */
725 if ((dist > PFIREDIST) ||
726 ((dist > PFIREDIST / 2) &&
727 (PL_TYPE(*l) == PLWHOLE))) /* if not within range */
728 continue; /* go on to next playert */
729 if (((p->p_swar | p->p_hostile) & l->pl_owner)
730 || ((l->pl_owner == NOBODY)
731 #if 1
732 && (l->pl_hostile & p->p_team)
733 #else
734 && (l->pl_torbit & (p->p_team << 4))
735 #endif
736 && (l->pl_armies != 0))
737 || (PL_TYPE(*l) == PLWHOLE) || (PL_TYPE(*l) == PLSTAR))
738 {
739 dam = l->pl_armies / 7 + 2; /* calc the damage */
740 if (PL_TYPE(*l) == PLWHOLE)
741 { /* if a wormhole... */
742 /* ...place outside the new wormhole's radius. */
743 if ((wh_effect[SS_WARP] && !(p->p_flags & PFWARP))
744 || (!wh_effect[SS_WARP]))
745 {
746 p->p_x = l->pl_armies +
747 (((PLFIREDIST / 2) + 50) * Cos[p->p_dir]);
748 p->p_y = l->pl_radius +
749 (((PLFIREDIST / 2) + 50) * Sin[p->p_dir]);
750 }
751 if ((p->p_speed > (p->p_ship.s_imp.maxspeed / 2)) &&
752 (wh_effect[SS_IMPULSE]))
753 {
754 dam = ((p->p_ship.s_mass / 100) * (p->p_speed -
755 p->p_ship.s_imp.maxspeed / 2));
756 }
757 else
758 dam = 0;
759
760 }
761 else if (PL_TYPE(*l) == PLSTAR) /* if planet is a star */
762 dam = 150; /* do massive damage */
763 /*
764 * this needs to be reworked and most of it jammed into
765 * inflict_damage
766 */
767 p->p_whodead = i; /* which planet is shooting */
768 if (dam > 0 && inflict_damage(0, 0, p, dam, KPLANET))
769 {
770 struct player *killer = 0;
771 p->p_whydead = KPLANET; /* set killed by a planet */
772 if (PL_TYPE(*l) == PLSTAR)
773 { /* killed by star? */
774 #ifdef GIVESTARKILLS
775 int pln;
776 for (pln = 0, killer = &players[0];
777 pln < MAXPLAYER;
778 pln++, killer++)
779 {
780 if (killer->p_status != PALIVE)
781 continue;
782 if (!friendly(killer, p) && killer->p_tractor == p->p_no
783 && killer->p_flags & (PFTRACT | PFPRESS))
784 {
785
786 killer->p_kills += 1 + (p->p_armies + p->p_kills) / 10;
787 killerstats(killer->p_no, p);
788 checkmaxkills(killer->p_no);
789 break;
790 }
791 }
792 if (pln >= MAXPLAYER)
793 killer = 0;
794 #endif
795 }
796 killmess(p, killer);
797 tlog_plankill(p, l, killer);
798 }
799 }
800 }
801 /* found the boost for this player, make adjustments if in warp [BDyess] */
802 if (configvals->warpzone && p->p_flags & PFWARP)
803 {
804 if (boost == 0 && p->p_zone > 0)
805 { /* did get warp bonus, lost it */
806 if (p->p_desspeed > p->p_ship.s_warp.maxspeed)
807 p->p_desspeed = p->p_ship.s_warp.maxspeed;
808 }
809 else if (boost < 0 && p->p_zone >= 0)
810 { /* warp no longer allowed */
811 p->p_desspeed = p->p_ship.s_imp.maxspeed;
812 if (!configvals->warpdecel)
813 p->p_flags &= ~PFWARP;
814 }
815 }
816 p->p_zone = boost;
817 }
818 }
819
820
821
822
823 /*---------------------------------REVOLT---------------------------------*/
824 /*
825 * This function does the revolt of a planet. It updates the revolt timer
826 * and prints the messages that warn the team.
827 */
828
829 void
830 revolt(l)
831 struct planet *l; /* the planet to check */
832 {
833 if (!configvals->revolts)
834 return;
835
836 if (l->pl_trevolt > 0)
837 { /* revolt timer running? */
838 char buf[80]; /* to sprintf into */
839
840 {
841 int i;
842 for (i = 0; i < MAXPLAYER; i++)
843 {
844 if (players[i].p_status == PALIVE
845 && (players[i].p_flags & (PFORBIT | PFDOCK)) == PFORBIT
846 && players[i].p_planet == l->pl_no
847 && players[i].p_team == l->pl_owner)
848 return; /* orbiting ship delays revolt */
849 }
850 }
851
852 l->pl_trevolt--; /* dec the timer */
853 if ((l->pl_trevolt == 0) && (l->pl_armies > 2))
854 {
855 l->pl_trevolt = 0; /* turn off revolt timer */
856 sprintf(buf, "The revolution on %s has been put down.",
857 l->pl_name); /* get message to display */
858 pmessage(buf, l->pl_owner, MTEAM | MCONQ, "PREFECT->");
859 }
860 else if ((l->pl_trevolt == 0) && (l->pl_armies == 2))
861 {
862 l->pl_trevolt = STARTREV; /* more time til last army */
863 l->pl_armies--; /* kill one army */
864 l->pl_tinfo[l->pl_owner].armies = l->pl_armies;
865 l->pl_tinfo[l->pl_owner].timestamp = status->clock;
866 sprintf(buf, "We cannot hold out much longer on %s",
867 l->pl_name); /* get message to display */
868 pmessage(buf, l->pl_owner, MTEAM | MCONQ, "PREFECT->");
869 }
870 else if (l->pl_trevolt == 0)
871 {
872 l->pl_trevolt = 0; /* revolution succeeded */
873 sprintf(buf, "The planet %s has been lost to revolutionaries",
874 l->pl_name); /* get message to display */
875 pmessage(buf, l->pl_owner, MTEAM | MCONQ, "PREFECT->");
876
877 tlog_revolt(l);
878
879 l->pl_tinfo[l->pl_owner].timestamp = status->clock;
880 l->pl_tinfo[l->pl_owner].owner = NOBODY;
881 l->pl_owner = NOBODY;
882 l->pl_flags |= PLREDRAW; /* slate for redraw */
883 checkwin(enemy_admiral(-1)); /* check for game end */
884
885 }
886 }
887 else
888 { /* no revolt timer--check for start */
889 if ((l->pl_armies <= 2) && (!(l->pl_armies == 0))
890 && ((lrand48() % 1000) <= REVOLT))
891 {
892 char buf[80]; /* to sprintf message into */
893
894 sprintf(buf, "There is civil unrest on %s", l->pl_name);
895 pmessage(buf, l->pl_owner, MTEAM | MCONQ, "PREFECT>>");
896 l->pl_trevolt = STARTREV; /* time before revolution */
897 }
898 }
899 }
900
901 void
902 check_revolt()
903 {
904 static int planetlist[MAXPLANETS];
905 static int count = 0;
906 int idx;
907 struct planet *l;
908
909 if (!status->tourn)
910 return;
911
912 if (count < 1)
913 fill_planets(planetlist, &count, -1);
914
915 idx = planetlist[--count];
916 l = &planets[idx];
917
918 if (l->pl_armies > 0 && l->pl_owner != NOBODY)
919 revolt(l);
920 }
921
922 /*-------------------------------------------------------------------------*/
923
924
925
926
927
928
929 /* struct planet *stars[NUMPLANETS + 1]; */
930
931 static void
932 build_stars_array()
933 {
934 int i;
935 struct planet *pl;
936
937 for (i = 0; i < NUMPLANETS; i++)
938 {
939 pl = &planets[i];
940 if (PL_TYPE(*pl) == PLSTAR)
941 stars[pl->pl_system] = i;
942 }
943 }
944
945 /*------------------------------VISIBLE FUNCTIONS-------------------------*/
946
947 /*-------------------------------GEN_PLANETS-------------------------------*/
948 /*
949 * This function generates a number of random planets. The planets are
950 * arranged in systems and are also placed so that they are not too close to
951 * any other planets. The races are then given home planets.
952 */
953
954 void
955 gen_planets()
956 {
957 int i;
958 struct planet *pl;
959
960 status->clock = 0; /* reset the timestamp clock */
961
962 switch (configvals->galaxygenerator)
963 {
964 case 2:
965 gen_galaxy_2(); /* Bob Forsman's compact galaxy generator */
966 break;
967 case 3:
968 gen_galaxy_3(); /* Heath's better race placement galaxy
969 * generator */
970 break;
971 case 4:
972 gen_galaxy_4(); /* Mike's Bronco emulator */
973 break;
974 case 5:
975 gen_galaxy_5(); /* Mike's small-galaxy generator */
976 break;
977 case 6:
978 gen_galaxy_6(); /* Brandon's hack on Heath's to give 2 */
979 break; /* systems to each race */
980 case 7:
981 gen_galaxy_7(); /* Eric Dormans deepspace galaxy gen, rooted
982 * in galaxy gen 6. */
983 break;
984 case 1:
985 default:
986 gen_galaxy_1(); /* original paradiseII galaxy generator */
987 break;
988 }
989
990 if (configvals->galaxygenerator != 4)
991 {
992 /* gotta do this before they are sorted */
993 for (i = 0; i < NUMPLANETS; i++)
994 {
995 pl = &planets[i];
996 if (PL_TYPE(*pl) == PLSTAR ||
997 ((pl->pl_system == 0) && (PL_TYPE(*pl) != PLWHOLE)))
998 {
999 pl->pl_radius = 0;
1000 pl->pl_angle = 0;
1001 }
1002 else if (PL_TYPE(*pl) != PLWHOLE)
1003 {
1004 int dx, dy;
1005 dx = pl->pl_x - planets[pl->pl_system - 1].pl_x;
1006 dy = pl->pl_y - planets[pl->pl_system - 1].pl_y;
1007 pl->pl_radius = ihypot(dx, dy);
1008 pl->pl_angle = atan2((double) dy, (double) dx);
1009 }
1010 }
1011 sortnames(); /* sort the names of planets */
1012 build_stars_array();
1013 if (configvals->neworbits)
1014 pl_neworbit();
1015 generate_terrain();
1016 }
1017 }
1018
1019 void
1020 pl_neworbit()
1021 /*
1022 * rearranges a pre-existing galaxy setup such that planets orbit at more
1023 * "unique" distances from their star. Asteroids look and probably play bad
1024 * when all the planets are approx. the same dist from the star, so I'd
1025 * suggest turning this on if you plan to have asteroids or orbiting planets
1026 * on your server. I'd suggest turning it on even if you don't. :) -MDM
1027 */
1028 {
1029 register int i, j;
1030 register struct planet *p;
1031 register int numStars = 0, planetsThisStar = 0;
1032 #ifndef IRIX
1033 int planetList[NUMPLANETS];
1034 #else
1035 int planetList[70];
1036 #endif
1037
1038 /* find the number of stars */
1039 for (i = 0; i < MAXPLANETS; i++)
1040 if (PL_TYPE(planets[i]) == PLSTAR)
1041 numStars++;
1042
1043 /* for each star, find the number of planets, and the average distance */
1044
1045 for (i = 1; i <= numStars; i++)
1046 {
1047 planetsThisStar = 0;
1048 for (j = 0; j < MAXPLANETS; j++)
1049 if (planets[j].pl_system == i)
1050 planetList[planetsThisStar++] = j;
1051
1052 /*
1053 * now move the planets such that each planet we came across gets its
1054 * previous distance from it's star, times (it's position in the
1055 * planetList array)/(planetsThisStar/1.6). also make sure that new
1056 * radius isin't so close to star ship can't orbit it. Heh. Separate
1057 * the men from the boyz, eh?
1058 */
1059
1060 for (j = 0; j < planetsThisStar; j++)
1061 {
1062 planets[planetList[j]].pl_radius =
1063 (int) ((float) planets[planetList[j]].pl_radius *
1064 ((float) (j + 1) / (float) (planetsThisStar / 1.6))) + 1500;
1065 planets[planetList[j]].pl_x =
1066 planets[stars[i]].pl_x +
1067 (int) ((float) cos(planets[planetList[j]].pl_angle) *
1068 (float) planets[planetList[j]].pl_radius);
1069 planets[planetList[j]].pl_y =
1070 planets[stars[i]].pl_y +
1071 (int) ((float) sin(planets[planetList[j]].pl_angle) *
1072 (float) planets[planetList[j]].pl_radius);
1073 }
1074 }
1075 }
1076
1077 void
1078 moveplanets()
1079 {
1080 register int i; /* for looping */
1081 register struct planet *l; /* to point to individual plaent */
1082
1083 if (stars[1] < 0)
1084 build_stars_array();
1085
1086 /* totally experimental planet moving stuff */
1087 for (i = 0; i < NUMPLANETS; i++)
1088 {
1089 int x, y;
1090 double r;
1091 l = &planets[i];
1092 if (PL_TYPE(*l) == PLSTAR || l->pl_system == 0)
1093 continue; /* write code for them another time */
1094
1095 r = l->pl_radius;
1096 l->pl_angle += configvals->planupdspd * 1e2 / sqrt(r * r * r);
1097 if (l->pl_angle > 2 * M_PI)
1098 l->pl_angle -= 2 * M_PI;
1099 x = planets[stars[l->pl_system]].pl_x + cos(l->pl_angle) * l->pl_radius;
1100 y = planets[stars[l->pl_system]].pl_y + sin(l->pl_angle) * l->pl_radius;
1101 move_planet(i, x, y, 1);
1102 }
1103 }
1104
1105
1106 /*
1107 * This function pops the armies on planets. It now uses the tables that are
1108 * in this module. Negative growth is supported.
1109 */
1110
1111 static void
1112 pop_one_planet1(l)
1113 struct planet *l;
1114 {
1115 int r; /* to hold resource index */
1116 int a; /* to hold atmosphere index */
1117 int t; /* temp var */
1118 float ft; /* another temp */
1119
1120 r = (l->pl_flags & PLRESMASK) >> PLRESSHIFT; /* get resource bits */
1121 r = restores[r]; /* convert to 3 bits */
1122 a = l->pl_flags & PLATMASK; /* get atmosphere bits */
1123 a = a >> PLATSHIFT; /* shift to lower two bits of int */
1124
1125 #ifdef UFL
1126 t = status2->league ? popchance[a][r] : 8;
1127 #else
1128 t = popchance[a][r]; /* get pop chance */
1129 #endif
1130 if (t < lrand48() % 100) /* if planet misses chance */
1131 return; /* then on to next planet */
1132 ft = popmult[a][r]; /* get pop multiplier */
1133 if (ft >= 0)
1134 { /* positive multiplier */
1135 int incr;
1136
1137 if (l->pl_armies >= popcap[a][r])
1138 return;
1139
1140 if (l->pl_armies < 4) /* chance of going over four */
1141 l->pl_flags |= PLREDRAW; /* slate planet for redraw */
1142 if (configvals->new_army_growth)
1143 #ifdef AEDILE
1144 incr = 0.5 + ft * 2.0 * (float) (lrand48() % 6 + 3);
1145 #else
1146 incr = 1 + 0.5 + ft * (float) (l->pl_armies);
1147 #endif
1148 else
1149 /* what about agri? */
1150 incr = 1 + lrand48() % 3; /* bronco is always 1-3 armies/pop */
1151 tlog_pop(l, incr);
1152 l->pl_armies += incr; /* add on multiplier armies */
1153 l->pl_tinfo[l->pl_owner].armies = l->pl_armies;
1154 l->pl_tinfo[l->pl_owner].timestamp = status->clock;
1155 }
1156 else
1157 { /* negative multiplier */
1158 int decr;
1159 if (l->pl_armies < 4) /* no killing all the armies on */
1160 return; /* a planet */
1161 l->pl_flags |= PLREDRAW; /* slate planet for redraw */
1162 decr = 1 + 0.5 - ft * (float) (l->pl_armies);
1163 tlog_pop(l, -decr);
1164 l->pl_armies -= decr; /* subtract armies */
1165 l->pl_armies = (l->pl_armies < 0) ? 0 : l->pl_armies;
1166 if (l->pl_armies <= 0)
1167 { /* if all died then */
1168 l->pl_armies = 0; /* no negative armies */
1169 l->pl_tinfo[l->pl_owner].armies = 0; /* old owner knows */
1170 l->pl_tinfo[l->pl_owner].timestamp = status->clock;
1171 l->pl_tinfo[l->pl_owner].owner = NOBODY;
1172 l->pl_owner = NOBODY; /* planet is neutral */
1173 }
1174 l->pl_tinfo[l->pl_owner].armies = l->pl_armies;
1175 l->pl_tinfo[l->pl_owner].timestamp = status->clock;
1176 if (l->pl_armies == 0) /* if all armies died */
1177 checkwin(enemy_admiral(-1)); /* check if game over */
1178 }
1179 }
1180 /*
1181 * */
1182
1183 static void
1184 pop_one_planet2(l)
1185 struct planet *l;
1186 {
1187 int delta = 0;
1188 int atmosphere = (l->pl_flags & PLATMASK) >> PLATSHIFT;
1189 int surface = (l->pl_flags & PLSURMASK) >> PLSURSHIFT;
1190
1191 if (l->pl_armies < 4 && (l->pl_flags & PLAGRI))
1192 delta++;
1193
1194 if (atmosphere == 0)
1195 {
1196 if (l->pl_armies >= 4 && drand48() < 0.5)
1197 {
1198 delta--;
1199 }
1200 }
1201 else if (atmosphere < 3)
1202 {
1203 if (drand48() <
1204 ((atmosphere == 1)
1205 ? (l->pl_armies < 4 ? 0.2 : 0.1)
1206 : (l->pl_armies < 4 ? 0.5 : 0.2)))
1207 {
1208 delta++;
1209 }
1210 }
1211 else
1212 {
1213 if (drand48() < (l->pl_armies < 4 ? 0.3 : 0.2))
1214 {
1215 static int table[] = {2, 2, 2, 3, 3, 3, 4, 4};
1216 int max = table[surface];
1217 delta++;
1218 if (l->pl_flags & PLAGRI && l->pl_armies >= 4)
1219 max++; /* armies<4 handled at top */
1220 delta += lrand48() % max;
1221 }
1222 }
1223
1224 if (l->pl_armies == 0 && delta > 1)
1225 delta = 1; /* training that first army is tough */
1226
1227 tlog_pop(l, delta);
1228
1229 if (delta > 0 &&
1230 l->pl_armies > popcap[atmosphere]
1231 [restores[(l->pl_flags & PLRESMASK) >> PLRESSHIFT]])
1232 delta = 0;
1233 l->pl_armies += delta;
1234
1235 /*
1236 * I doubt this if statement will ever get executed unless someone's
1237 * frobbing shmem
1238 */
1239 if (l->pl_armies <= 0)
1240 { /* if all died then */
1241 l->pl_armies = 0; /* no negative armies */
1242
1243 tlog_revolt(l); /* well, not exactly. */
1244
1245 l->pl_tinfo[l->pl_owner].armies = 0; /* old owner knows */
1246 l->pl_tinfo[l->pl_owner].timestamp = status->clock;
1247 l->pl_tinfo[l->pl_owner].owner = NOBODY;
1248 l->pl_owner = NOBODY; /* planet is neutral */
1249 checkwin(enemy_admiral(-1));/* check if game over */
1250 }
1251
1252 l->pl_tinfo[l->pl_owner].armies = l->pl_armies;
1253 l->pl_tinfo[l->pl_owner].timestamp = status->clock;
1254 }
1255
1256 void
1257 pop_one_planet(l)
1258 struct planet *l;
1259 {
1260 #if 0
1261 printf("popping planet #%d %x\n", l->pl_no, l->pl_owner);
1262 fflush(stdout);
1263 #endif
1264
1265 switch (configvals->popscheme)
1266 {
1267 case 1:
1268 pop_one_planet2(l);
1269 break;
1270 default:
1271 case 0:
1272 pop_one_planet1(l);
1273 break;
1274 }
1275 }
1276
1277
1278 /*-------------------------------UDPLANETS----------------------------------*/
1279
1280 void
1281 fill_planets(plist, count, owner)
1282 int *plist; /* array */
1283 int *count; /* scalar */
1284 int owner;
1285 {
1286 int i;
1287 *count = 0;
1288 for (i = 0; i < configvals->numplanets; i++)
1289 {
1290 if (owner < 0 || planets[i].pl_owner == owner)
1291 plist[(*count)++] = i;
1292 }
1293
1294 for (i = *count - 1; i > 0; i--)
1295 {
1296 int idx = lrand48() % (i + 1);
1297 int temp = plist[idx];
1298 plist[idx] = plist[i];
1299 plist[i] = temp;
1300 }
1301 }
1302
1303 int
1304 find_other_team(teammask)
1305 int teammask;
1306 {
1307 int counts[NUMTEAM];
1308 int i;
1309 for (i = 0; i < NUMTEAM; i++)
1310 counts[i] = 0;
1311 for (i = 0; i < MAXPLAYER; i++)
1312 {
1313 int teamidx = mask_to_idx(players[i].p_team);
1314 if (teamidx >= 0 && teamidx < NUMTEAM && !(teammask & (1 << teamidx)))
1315 counts[teamidx]++;
1316 }
1317
1318 {
1319 int max = -1;
1320 int rval = 0;
1321 for (i = 0; i < NUMTEAM; i++)
1322 {
1323 if (counts[i] > max && !(teammask & (1 << i)))
1324 {
1325 max = counts[i];
1326 rval = 1 << i;
1327 }
1328 }
1329 return rval;
1330 }
1331 }
1332
1333 void
1334 popplanets()
1335 {
1336 register int i; /* for looping */
1337 register struct planet *l; /* to point to individual plaent */
1338
1339 if (!status->tourn) /* check t-mode */
1340 return; /* do not pop planets */
1341
1342 switch (configvals->popchoice)
1343 {
1344 case 0:
1345 {
1346 static int fuse = 0;
1347 if (++fuse < PLANETFUSE)
1348 return; /* nothing to do */
1349 fuse = 0;
1350 for (i = 0, l = &planets[i]; i < NUMPLANETS; i++, l++)
1351 {
1352 if ((l->pl_armies == 0) ||
1353 (PL_TYPE(*l) == PLSTAR) ||
1354 (PL_TYPE(*l) == PLWHOLE)) /* if no armies to pop */
1355 continue; /* go to next planet */
1356 #if 0
1357 if (l->pl_owner != NOBODY) /* only team planets can revolt */
1358 revolt(l); /* check for revolt */
1359 #endif
1360 pop_one_planet(l);
1361 }
1362 } break;
1363 case 1:
1364 {
1365 #if 0
1366 static int indplanets[MAXPLANETS];
1367 static int indcount = 0;
1368 #endif
1369 static int Aplanets[MAXPLANETS];
1370 static int Acount = 0, Amask = 0;
1371 static int Bplanets[MAXPLANETS];
1372 static int Bcount = 0, Bmask = 0;
1373
1374 int INDchance;
1375 float Achance, Bchance;
1376 float f;
1377
1378 /* make sure there's planets in the lists */
1379 #if 0
1380 if (indcount < 1)
1381 fill_planets(indplanets, &indcount, NOBODY);
1382 #endif
1383 if (Acount < 1)
1384 {
1385 Amask = find_other_team(Bmask);
1386 fill_planets(Aplanets, &Acount, Amask);
1387 }
1388 if (Bcount < 1)
1389 {
1390 Bmask = find_other_team(Amask);
1391 fill_planets(Bplanets, &Bcount, Bmask);
1392 }
1393
1394 /* figure out the probabilities */
1395 INDchance = Achance = Bchance = 0;
1396 for (i = 0; i < configvals->numplanets; i++)
1397 {
1398 if (planets[i].pl_owner == Amask)
1399 Achance += 1.0;
1400 else if (planets[i].pl_owner == Bmask)
1401 Bchance += 1.0;
1402 else if (!((PL_TYPE(planets[i]) == PLSTAR) ||
1403 (PL_TYPE(planets[i]) == PLWHOLE)))
1404 /* if (planets[i].pl_owner == NOBODY) */
1405 INDchance += 1.0;
1406 }
1407
1408 #ifdef LOOSING_ADVANTAGE
1409 {
1410 double la = LOOSING_ADVANTAGE;
1411 if (Achance < Bchance)
1412 Achance *= (la - (la - 1) * Achance / Bchance);
1413 else
1414 Bchance *= (la - (la - 1) * Bchance / Achance);
1415 }
1416 #endif
1417
1418 f = drand48() * (INDchance + Achance + Bchance);
1419 if (f < INDchance)
1420 {
1421 #if 0 /* 3rd-race planets and INDs don't pop */
1422 pop_one_planet(&planets[indplanets[--indcount]]);
1423 #endif
1424 }
1425 else if (f - INDchance < Achance)
1426 {
1427 pop_one_planet(&planets[Aplanets[--Acount]]);
1428 }
1429 else
1430 {
1431 pop_one_planet(&planets[Bplanets[--Bcount]]);
1432 }
1433
1434 } break;
1435 }
1436 }
1437
1438
1439
1440
1441
1442 /*----------------------------------PLFIGHT--------------------------------*/
1443 /*
1444 * This function does the fighting for a planet. It decs the warning timer
1445 * and clears the REDRAW flag. It then handles the bombing for the players.
1446 * It then goes on to see if a player is visible to the other team by
1447 * checking the closeness of other players. The planets are then checked to
1448 * see if they are close enough to fire on enemy players.
1449 */
1450
1451 void
1452 plfight()
1453 {
1454 register int h; /* looping vars */
1455 register struct planet *l; /* for looping through planets */
1456
1457 for (h = 0, l = &planets[h]; h < NUMPLANETS; h++, l++)
1458 {
1459 l->pl_flags &= ~PLREDRAW; /* clear the PLDRAW flag */
1460 if (l->pl_warning > 0) /* check if timer needs dec */
1461 l->pl_warning--; /* dec the warning timer */
1462 }
1463 pbomb(); /* go do bombing for players */
1464 pvisible(); /* check visibility w/ other players */
1465 pfire(); /* let planets fire on other players */
1466 }
1467
1468
1469
1470
1471 /*-------------------------------SAVE_PLANETS-----------------------------*/
1472 /*
1473 * This function saves the planets structure to disk. The plfd variable is a
1474 * handle on the previously opened .planets file. The function also saves
1475 * the status to the glfd file.
1476 */
1477
1478 void
1479 save_planets()
1480 {
1481 if (plfd >= 0)
1482 { /* if plfd file open */
1483 (void) lseek(plfd, (long) 0, 0); /* save the planets */
1484 (void) write(plfd, (char *) planets, sizeof(struct planet) * MAXPLANETS);
1485 }
1486 if (glfd >= 0)
1487 { /* if glfd file open then */
1488 (void) lseek(glfd, (long) 0, 0); /* save the status */
1489 (void) write(glfd, (char *) status, sizeof(struct status));
1490 }
1491 }
1492
1493 /*-------------------------------------------------------------------------*/
1494
1495
1496
1497 /*----------END OF FILE--------*/