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