1 /*
2  * XPilot NG, a multiplayer space war game.
3  *
4  * Copyright (C) 2000-2004 by
5  *
6  *      Uoti Urpala          <uau@users.sourceforge.net>
7  *      Kristian S�derblom   <kps@users.sourceforge.net>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #include "xpserver.h"
25 
26 /* polygon map format related stuff */
27 int num_edges, max_edges;
28 
29 int *edgeptr;
30 int *estyleptr;
31 static int ptscount = -1, ecount;
32 
33 struct polystyle pstyles[256];
34 struct edgestyle estyles[256] =
35 {{"internal", 0, 0, 0}};	/* Style 0 is always this special style */
36 struct bmpstyle  bstyles[256];
37 poly_t *pdata;
38 
39 int num_pstyles, num_bstyles, num_estyles = 1; /* "Internal" edgestyle */
40 int max_bases, max_balls, max_polys,max_echanges; /* !@# make static after testing done */
41 static int current_estyle, current_group, is_decor;
42 
Create_group(int type,int team,hitmask_t hitmask,bool (* hitfunc)(group_t * gp,const move_t * move),int mapobj_ind)43 static int Create_group(int type, int team, hitmask_t hitmask,
44 			bool (*hitfunc)(group_t *gp, const move_t *move),
45 			int mapobj_ind)
46 {
47     group_t gp;
48 
49     gp.type = type;
50     gp.team = team;
51     gp.hitmask = hitmask;
52     gp.hitfunc = hitfunc;
53     gp.mapobj_ind = mapobj_ind;
54 
55     if (current_group != 0) {
56 	warn("Broken map: map object defined inside another.");
57 	exit(1);
58     }
59 
60     current_group = num_groups;
61     STORE(group_t, groups, num_groups, max_groups, gp);
62     return current_group;
63 }
64 
Groups_init(void)65 void Groups_init(void)
66 {
67     Create_group(FILLED, TEAM_NOT_SET, 0, NULL, NO_IND);
68     current_group = 0;
69 }
70 
P_edgestyle(const char * id,int width,int color,int style)71 void P_edgestyle(const char *id, int width, int color, int style)
72 {
73     if (num_estyles > 255) {
74 	warn("Too many edgestyles");
75 	exit(1);
76     }
77 
78     strlcpy(estyles[num_estyles].id, id, sizeof(estyles[0].id));
79     estyles[num_estyles].color = color;
80     estyles[num_estyles].width = width;
81     estyles[num_estyles].style = style;
82     num_estyles++;
83 }
84 
P_polystyle(const char * id,int color,int texture_id,int defedge_id,int flags)85 void P_polystyle(const char *id, int color, int texture_id, int defedge_id,
86 		 int flags)
87 {
88     if (num_pstyles > 255) {
89 	warn("Too many polygon styles");
90 	exit(1);
91     }
92     if (defedge_id == 0) {
93 	warn("Polygon default edgestyle cannot be omitted or set "
94 	     "to 'internal'!");
95 	exit(1);
96     }
97 
98     strlcpy(pstyles[num_pstyles].id, id, sizeof(pstyles[0].id));
99     pstyles[num_pstyles].color = color;
100     pstyles[num_pstyles].texture_id = texture_id;
101     pstyles[num_pstyles].defedge_id = defedge_id;
102     pstyles[num_pstyles].flags = flags;
103     num_pstyles++;
104 }
105 
106 
P_bmpstyle(const char * id,const char * filename,int flags)107 void P_bmpstyle(const char *id, const char *filename, int flags)
108 {
109     if (num_bstyles > 255) {
110 	warn("Too many bitmap styles");
111 	exit(1);
112     }
113     strlcpy(bstyles[num_bstyles].id, id, sizeof(bstyles[0].id));
114     strlcpy(bstyles[num_bstyles].filename, filename,
115 	    sizeof(bstyles[0].filename));
116     bstyles[num_bstyles].flags = flags;
117     num_bstyles++;
118 }
119 
120 /* current vertex */
121 static clpos_t P_cv;
122 
P_start_polygon(clpos_t pos,int style)123 void P_start_polygon(clpos_t pos, int style)
124 {
125     poly_t t;
126 
127     if (!World_contains_clpos(pos)) {
128 	warn("Polygon start point (%d, %d) is not inside the map"
129 	     "(0 <= x < %d, 0 <= y < %d)",
130 	     pos.cx, pos.cy, world->cwidth, world->cheight);
131 	exit(1);
132     }
133     if (style == -1) {
134 	warn("Currently you must give polygon style, no default");
135 	exit(1);
136     }
137 
138     ptscount = 0;
139     P_cv = pos;
140     t.pos = pos;
141     t.group = current_group;
142     t.edges = num_edges;
143     t.style = style;
144     t.current_style = style;
145     t.destroyed_style = style; /* may be changed */
146     t.estyles_start = ecount;
147     t.is_decor = is_decor;
148 
149     t.update_mask = 0;
150     t.last_change = frame_loops;
151 
152     current_estyle = pstyles[style].defedge_id;
153     STORE(poly_t, pdata, num_polys, max_polys, t);
154 }
155 
156 
P_offset(clpos_t offset,int edgestyle)157 void P_offset(clpos_t offset, int edgestyle)
158 {
159     int i, offcx = offset.cx, offcy = offset.cy;
160 
161     if (ptscount < 0) {
162 	warn("Can't have <Offset> outside <Polygon>.");
163 	exit(1);
164     }
165 
166     if (offcx == 0 && offcy == 0) {
167 	/*
168 	 * Don't warn about zero length edges for xp maps, since
169 	 * the conversion creates such edges.
170 	 */
171 	if (is_polygon_map)
172 	    warn("Edge with zero length");
173 	if (edgestyle != -1 && edgestyle != current_estyle) {
174 	    warn("Refusing to change edgestyle with zero-length edge");
175 	    exit(1);
176 	}
177 	return;
178     }
179 
180     if (edgestyle != -1 && edgestyle != current_estyle) {
181 	STORE(int, estyleptr, ecount, max_echanges, ptscount);
182 	STORE(int, estyleptr, ecount, max_echanges, edgestyle);
183 	current_estyle = edgestyle;
184     }
185 
186     P_cv.cx += offcx;
187     P_cv.cy += offcy;
188 
189     i = (MAX(ABS(offcx), ABS(offcy)) - 1) / POLYGON_MAX_OFFSET + 1;
190     for (;i > 0;i--) {
191 	STORE(int, edgeptr, num_edges, max_edges, offcx / i);
192 	STORE(int, edgeptr, num_edges, max_edges, offcy / i);
193 	offcx -= offcx / i;
194 	offcy -= offcy / i;
195 	ptscount++;
196     }
197 }
198 
P_vertex(clpos_t pos,int edgestyle)199 void P_vertex(clpos_t pos, int edgestyle)
200 {
201     clpos_t offset;
202 
203     offset.cx = pos.cx - P_cv.cx;
204     offset.cy = pos.cy - P_cv.cy;
205 
206     P_offset(offset, edgestyle);
207 }
208 
P_style(const char * state,int style)209 void P_style(const char *state, int style)
210 {
211     if (style == -1) {
212 	warn("<Style> needs a style id.");
213 	exit(1);
214     }
215 
216     if (ptscount < 0) {
217 	warn("Can't have <Style> outside <Polygon>.");
218 	exit(1);
219     }
220 
221     if (!strcmp(state, "destroyed"))
222 	pdata[num_polys - 1].destroyed_style = style;
223     else {
224 	warn("<Style> does not support state \"%s\".", state);
225 	exit(1);
226     }
227 }
228 
P_end_polygon(void)229 void P_end_polygon(void)
230 {
231     if (ptscount < 3) {
232 	warn("Polygon with less than 3 edges?? (start %d, %d)",
233 	     pdata[num_polys - 1].pos.cx, pdata[num_polys - 1].pos.cy);
234 	exit(1);
235     }
236 
237     /* kps - add check that e.g. cannons have "destroyed" state <Style> ? */
238 
239     pdata[num_polys - 1].num_points = ptscount;
240     pdata[num_polys - 1].num_echanges
241 	= ecount -pdata[num_polys - 1].estyles_start;
242     STORE(int, estyleptr, ecount, max_echanges, INT_MAX);
243     ptscount = -1;
244 }
245 
P_start_ballarea(void)246 int P_start_ballarea(void)
247 {
248     return Create_group(TREASURE,
249 			TEAM_NOT_SET,
250 			BALL_BIT,
251 			NULL,
252 			NO_IND);
253 }
254 
P_end_ballarea(void)255 void P_end_ballarea(void)
256 {
257     current_group = 0;
258 }
259 
P_start_balltarget(int team,int treasure_ind)260 int P_start_balltarget(int team, int treasure_ind)
261 {
262     return Create_group(TREASURE,
263 			team,
264 			NONBALL_BIT,
265 			Balltarget_hitfunc,
266 			treasure_ind);
267 }
268 
P_end_balltarget(void)269 void P_end_balltarget(void)
270 {
271     current_group = 0;
272 }
273 
P_start_target(int target_ind)274 int P_start_target(int target_ind)
275 {
276     target_t *targ = Target_by_index(target_ind);
277 
278     targ->group = Create_group(TARGET,
279 			       targ->team,
280 			       Target_hitmask(targ),
281 			       NULL,
282 			       target_ind);
283     return targ->group;
284 }
285 
P_end_target(void)286 void P_end_target(void)
287 {
288     current_group = 0;
289 }
290 
P_start_cannon(int cannon_ind)291 int P_start_cannon(int cannon_ind)
292 {
293     cannon_t *cannon = Cannon_by_index(cannon_ind);
294 
295     cannon->group = Create_group(CANNON,
296 				 cannon->team,
297 				 Cannon_hitmask(cannon),
298 				 Cannon_hitfunc,
299 				 cannon_ind);
300     return cannon->group;
301 }
302 
P_end_cannon(void)303 void P_end_cannon(void)
304 {
305     current_group = 0;
306 }
307 
P_start_wormhole(int wormhole_ind)308 int P_start_wormhole(int wormhole_ind)
309 {
310     wormhole_t *wormhole = Wormhole_by_index(wormhole_ind);
311 
312     wormhole->group = Create_group(WORMHOLE,
313 				   TEAM_NOT_SET,
314 				   Wormhole_hitmask(wormhole),
315 				   Wormhole_hitfunc,
316 				   wormhole_ind);
317     return wormhole->group;
318 }
319 
P_end_wormhole(void)320 void P_end_wormhole(void)
321 {
322     current_group = 0;
323 }
324 
P_start_friction_area(int fa_ind)325 int P_start_friction_area(int fa_ind)
326 {
327     friction_area_t *fa = FrictionArea_by_index(fa_ind);
328 
329     fa->group = Create_group(FRICTION,
330 			     TEAM_NOT_SET,
331 			     0,
332 			     Friction_area_hitfunc,
333 			     fa_ind);
334     return fa->group;
335 }
336 
P_end_friction_area(void)337 void P_end_friction_area(void)
338 {
339     current_group = 0;
340 }
341 
P_start_decor(void)342 void P_start_decor(void)
343 {
344     is_decor = 1;
345 }
346 
P_end_decor(void)347 void P_end_decor(void)
348 {
349     is_decor = 0;
350 }
351 
P_get_bmp_id(const char * s)352 int P_get_bmp_id(const char *s)
353 {
354     int i;
355 
356     for (i = 0; i < num_bstyles; i++)
357 	if (!strcmp(bstyles[i].id, s))
358 	    return i;
359     warn("Broken map: Undeclared bmpstyle %s", s);
360     exit(1);
361 }
362 
363 
P_get_edge_id(const char * s)364 int P_get_edge_id(const char *s)
365 {
366     int i;
367 
368     for (i = 0; i < num_estyles; i++)
369 	if (!strcmp(estyles[i].id, s))
370 	    return i;
371     warn("Broken map: Undeclared edgestyle %s", s);
372     exit(1);
373 }
374 
375 
P_get_poly_id(const char * s)376 int P_get_poly_id(const char *s)
377 {
378     int i;
379 
380     for (i = 0; i < num_pstyles; i++)
381 	if (!strcmp(pstyles[i].id, s))
382 	    return i;
383     warn("Broken map: Undeclared polystyle %s", s);
384     exit(1);
385 }
386 
P_set_hitmask(int group,hitmask_t hitmask)387 void P_set_hitmask(int group, hitmask_t hitmask)
388 {
389     assert(group >= 0);
390     assert(group < num_groups);
391     groups[group].hitmask = hitmask;
392 }
393