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