1 /*
2 * XPilot NG, a multiplayer space war game.
3 *
4 * Copyright (C) 1991-2001 by
5 *
6 * Bj�rn Stabell <bjoern@xpilot.org>
7 * Ken Ronny Schouten <ken@xpilot.org>
8 * Bert Gijsbers <bert@xpilot.org>
9 * Dick Balaska <dick@xpilot.org>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 #include "xpserver.h"
27
28 #define GRAV_RANGE 10
29
Compute_global_gravity(void)30 static void Compute_global_gravity(void)
31 {
32 int xi, yi, dx, dy;
33 double xforce, yforce, strength, theta;
34 vector_t *grav;
35
36 if (options.gravityPointSource == false) {
37 theta = (options.gravityAngle * PI) / 180.0;
38 xforce = cos(theta) * options.gravity;
39 yforce = sin(theta) * options.gravity;
40 for (xi = 0; xi < world->x; xi++) {
41 grav = world->gravity[xi];
42
43 for (yi = 0; yi < world->y; yi++, grav++) {
44 grav->x = xforce;
45 grav->y = yforce;
46 }
47 }
48 } else {
49 for (xi = 0; xi < world->x; xi++) {
50 grav = world->gravity[xi];
51 dx = (xi - options.gravityPoint.x) * BLOCK_SZ;
52 dx = WRAP_DX(dx);
53
54 for (yi = 0; yi < world->y; yi++, grav++) {
55 dy = (yi - options.gravityPoint.y) * BLOCK_SZ;
56 dy = WRAP_DX(dy);
57
58 if (dx == 0 && dy == 0) {
59 grav->x = 0.0;
60 grav->y = 0.0;
61 continue;
62 }
63 strength = options.gravity / LENGTH(dx, dy);
64 if (options.gravityClockwise) {
65 grav->x = dy * strength;
66 grav->y = -dx * strength;
67 }
68 else if (options.gravityAnticlockwise) {
69 grav->x = -dy * strength;
70 grav->y = dx * strength;
71 }
72 else {
73 grav->x = dx * strength;
74 grav->y = dy * strength;
75 }
76 }
77 }
78 }
79 }
80
81
Compute_grav_tab(vector_t grav_tab[GRAV_RANGE+1][GRAV_RANGE+1])82 static void Compute_grav_tab(vector_t grav_tab[GRAV_RANGE+1][GRAV_RANGE+1])
83 {
84 int x, y;
85 double strength;
86
87 grav_tab[0][0].x = grav_tab[0][0].y = 0;
88 for (x = 0; x < GRAV_RANGE+1; x++) {
89 for (y = (x == 0); y < GRAV_RANGE+1; y++) {
90 strength = pow((double)(sqr(x) + sqr(y)), -1.5);
91 grav_tab[x][y].x = x * strength;
92 grav_tab[x][y].y = y * strength;
93 }
94 }
95 }
96
97
Compute_local_gravity(void)98 static void Compute_local_gravity(void)
99 {
100 int xi, yi, i, gx, gy, ax, ay, dx, dy, gtype;
101 int first_xi, last_xi, first_yi, last_yi, mod_xi, mod_yi;
102 int min_xi, max_xi, min_yi, max_yi;
103 double force, fx, fy;
104 vector_t *v, *grav, *tab, grav_tab[GRAV_RANGE+1][GRAV_RANGE+1];
105
106 Compute_grav_tab(grav_tab);
107
108 min_xi = 0;
109 max_xi = world->x - 1;
110 min_yi = 0;
111 max_yi = world->y - 1;
112 if (BIT(world->rules->mode, WRAP_PLAY)) {
113 min_xi -= MIN(GRAV_RANGE, world->x);
114 max_xi += MIN(GRAV_RANGE, world->x);
115 min_yi -= MIN(GRAV_RANGE, world->y);
116 max_yi += MIN(GRAV_RANGE, world->y);
117 }
118 for (i = 0; i < Num_gravs(); i++) {
119 grav_t *g = Grav_by_index(i);
120
121 gx = CLICK_TO_BLOCK(g->pos.cx);
122 gy = CLICK_TO_BLOCK(g->pos.cy);
123 force = g->force;
124
125 if ((first_xi = gx - GRAV_RANGE) < min_xi)
126 first_xi = min_xi;
127 if ((last_xi = gx + GRAV_RANGE) > max_xi)
128 last_xi = max_xi;
129 if ((first_yi = gy - GRAV_RANGE) < min_yi)
130 first_yi = min_yi;
131 if ((last_yi = gy + GRAV_RANGE) > max_yi)
132 last_yi = max_yi;
133
134 gtype = g->type;
135
136 mod_xi = (first_xi < 0) ? (first_xi + world->x) : first_xi;
137 dx = gx - first_xi;
138 fx = force;
139 for (xi = first_xi; xi <= last_xi; xi++, dx--) {
140 if (dx < 0) {
141 fx = -force;
142 ax = -dx;
143 } else
144 ax = dx;
145
146 mod_yi = (first_yi < 0) ? (first_yi + world->y) : first_yi;
147 dy = gy - first_yi;
148 grav = &world->gravity[mod_xi][mod_yi];
149 tab = grav_tab[ax];
150 fy = force;
151 for (yi = first_yi; yi <= last_yi; yi++, dy--) {
152 if (dx || dy) {
153 if (dy < 0) {
154 fy = -force;
155 ay = -dy;
156 } else
157 ay = dy;
158
159 v = &tab[ay];
160 if (gtype == CWISE_GRAV || gtype == ACWISE_GRAV) {
161 grav->x -= fy * v->y;
162 grav->y += fx * v->x;
163 } else if (gtype == UP_GRAV || gtype == DOWN_GRAV)
164 grav->y += force * v->x;
165 else if (gtype == RIGHT_GRAV || gtype == LEFT_GRAV)
166 grav->x += force * v->y;
167 else {
168 grav->x += fx * v->x;
169 grav->y += fy * v->y;
170 }
171 }
172 else {
173 if (gtype == UP_GRAV || gtype == DOWN_GRAV)
174 grav->y += force;
175 else if (gtype == LEFT_GRAV || gtype == RIGHT_GRAV)
176 grav->x += force;
177 }
178 mod_yi++;
179 grav++;
180 if (mod_yi >= world->y) {
181 mod_yi = 0;
182 grav = world->gravity[mod_xi];
183 }
184 }
185 if (++mod_xi >= world->x)
186 mod_xi = 0;
187 }
188 }
189 /*
190 * We may want to free the world->gravity memory here
191 * as it is not used anywhere else.
192 * e.g.: free(world->gravity);
193 * world->gravity = NULL;
194 * world->NumGravs = 0;
195 * Some of the more modern maps have quite a few gravity symbols.
196 */
197 }
198
199
Compute_gravity(void)200 void Compute_gravity(void)
201 {
202 Compute_global_gravity();
203 Compute_local_gravity();
204 }
205