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 /*
29  * Fast conversion of 'num' into 'str' starting at position 'i', returns
30  * index of character after converted number.
31  */
num2str(int num,char * str,int i)32 static int num2str(int num, char *str, int i)
33 {
34     int	digits, t;
35 
36     if (num < 0) {
37 	str[i++] = '-';
38 	num = -num;
39     }
40     if (num < 10) {
41 	str[i++] = '0' + num;
42 	return i;
43     }
44     for (t = num, digits = 0; t; t /= 10, digits++)
45 	;
46     for (t = i+digits-1; t >= 0; t--) {
47 	str[t] = num % 10;
48 	num /= 10;
49     }
50     return i + digits;
51 }
52 
53 
54 #define MODS_BIT0	(1<<0)
55 #define MODS_BIT1	(1<<1)
56 
57 #define MODS_N_BIT0	(1<<0)		/* nuclear */
58 #define MODS_N_BIT1	(1<<1)		/* fullnuclear */
59 #define MODS_C_BIT	(1<<2)		/* cluster */
60 #define MODS_I_BIT	(1<<3)		/* implosion */
61 #define MODS_V_BIT0	(1<<4)		/* velocity */
62 #define MODS_V_BIT1	(1<<5)
63 #define MODS_X_BIT0	(1<<6)		/* mini */
64 #define MODS_X_BIT1	(1<<7)
65 #define MODS_Z_BIT0	(1<<8)		/* spread */
66 #define MODS_Z_BIT1	(1<<9)
67 #define MODS_B_BIT0	(1<<10)		/* power */
68 #define MODS_B_BIT1	(1<<11)
69 #define MODS_LS_BIT	(1<<12)		/* stun laser */
70 #define MODS_LB_BIT	(1<<13)		/* blinding laser */
71 
Get_nuclear_modifier(modifiers_t mods)72 static inline int Get_nuclear_modifier(modifiers_t mods)
73 {
74     int n0, n1;
75 
76     n0 = BIT(mods, MODS_N_BIT0) ? 1 : 0;
77     n1 = BIT(mods, MODS_N_BIT1) ? 1 : 0;
78 
79     return (n1 << 1) + n0;
80 }
Set_nuclear_modifier(modifiers_t * mods,int value)81 static inline void Set_nuclear_modifier(modifiers_t *mods, int value)
82 {
83     LIMIT(value, 0, MODS_NUCLEAR_MAX);
84     if (BIT(value, MODS_BIT0))
85 	SET_BIT(*mods, MODS_N_BIT0);
86     else
87 	CLR_BIT(*mods, MODS_N_BIT0);
88     if (BIT(value, MODS_BIT1))
89 	SET_BIT(*mods, MODS_N_BIT1);
90     else
91 	CLR_BIT(*mods, MODS_N_BIT1);
92 }
93 
Get_cluster_modifier(modifiers_t mods)94 static inline int Get_cluster_modifier(modifiers_t mods)
95 {
96     return (int) BIT(mods, MODS_C_BIT) ? 1 : 0;
97 }
Set_cluster_modifier(modifiers_t * mods,int value)98 static inline void Set_cluster_modifier(modifiers_t *mods, int value)
99 {
100     LIMIT(value, 0, 1);
101     if (value)
102 	SET_BIT(*mods, MODS_C_BIT);
103     else
104 	CLR_BIT(*mods, MODS_C_BIT);
105 }
106 
Get_implosion_modifier(modifiers_t mods)107 static inline int Get_implosion_modifier(modifiers_t mods)
108 {
109     return (int) BIT(mods, MODS_I_BIT) ? 1 : 0;
110 }
Set_implosion_modifier(modifiers_t * mods,int value)111 static inline void Set_implosion_modifier(modifiers_t *mods, int value)
112 {
113     LIMIT(value, 0, 1);
114     if (value)
115 	SET_BIT(*mods, MODS_I_BIT);
116     else
117 	CLR_BIT(*mods, MODS_I_BIT);
118 }
119 
Get_velocity_modifier(modifiers_t mods)120 static inline int Get_velocity_modifier(modifiers_t mods)
121 {
122     int v0, v1;
123 
124     v0 = BIT(mods, MODS_V_BIT0) ? 1 : 0;
125     v1 = BIT(mods, MODS_V_BIT1) ? 1 : 0;
126 
127     return (v1 << 1) + v0;
128 }
Set_velocity_modifier(modifiers_t * mods,int value)129 static inline void Set_velocity_modifier(modifiers_t *mods, int value)
130 {
131     LIMIT(value, 0, MODS_VELOCITY_MAX);
132     if (BIT(value, MODS_BIT0))
133 	SET_BIT(*mods, MODS_V_BIT0);
134     else
135 	CLR_BIT(*mods, MODS_V_BIT0);
136     if (BIT(value, MODS_BIT1))
137 	SET_BIT(*mods, MODS_V_BIT1);
138     else
139 	CLR_BIT(*mods, MODS_V_BIT1);
140 }
141 
Get_mini_modifier(modifiers_t mods)142 static inline int Get_mini_modifier(modifiers_t mods)
143 {
144     int x0, x1;
145 
146     x0 = BIT(mods, MODS_X_BIT0) ? 1 : 0;
147     x1 = BIT(mods, MODS_X_BIT1) ? 1 : 0;
148 
149     return (x1 << 1) + x0;
150 }
Set_mini_modifier(modifiers_t * mods,int value)151 static inline void Set_mini_modifier(modifiers_t *mods, int value)
152 {
153     LIMIT(value, 0, MODS_MINI_MAX);
154     if (BIT(value, MODS_BIT0))
155 	SET_BIT(*mods, MODS_X_BIT0);
156     else
157 	CLR_BIT(*mods, MODS_X_BIT0);
158     if (BIT(value, MODS_BIT1))
159 	SET_BIT(*mods, MODS_X_BIT1);
160     else
161 	CLR_BIT(*mods, MODS_X_BIT1);
162 }
163 
Get_spread_modifier(modifiers_t mods)164 static inline int Get_spread_modifier(modifiers_t mods)
165 {
166     int z0, z1;
167 
168     z0 = BIT(mods, MODS_Z_BIT0) ? 1 : 0;
169     z1 = BIT(mods, MODS_Z_BIT1) ? 1 : 0;
170 
171     return (z1 << 1) + z0;
172 }
Set_spread_modifier(modifiers_t * mods,int value)173 static inline void Set_spread_modifier(modifiers_t *mods, int value)
174 {
175     LIMIT(value, 0, MODS_SPREAD_MAX);
176     if (BIT(value, MODS_BIT0))
177 	SET_BIT(*mods, MODS_Z_BIT0);
178     else
179 	CLR_BIT(*mods, MODS_Z_BIT0);
180     if (BIT(value, MODS_BIT1))
181 	SET_BIT(*mods, MODS_Z_BIT1);
182     else
183 	CLR_BIT(*mods, MODS_Z_BIT1);
184 }
185 
Get_power_modifier(modifiers_t mods)186 static inline int Get_power_modifier(modifiers_t mods)
187 {
188     int b0, b1;
189 
190     b0 = BIT(mods, MODS_B_BIT0) ? 1 : 0;
191     b1 = BIT(mods, MODS_B_BIT1) ? 1 : 0;
192 
193     return (b1 << 1) + b0;
194 }
Set_power_modifier(modifiers_t * mods,int value)195 static inline void Set_power_modifier(modifiers_t *mods, int value)
196 {
197     LIMIT(value, 0, MODS_POWER_MAX);
198     if (BIT(value, MODS_BIT0))
199 	SET_BIT(*mods, MODS_B_BIT0);
200     else
201 	CLR_BIT(*mods, MODS_B_BIT0);
202     if (BIT(value, MODS_BIT1))
203 	SET_BIT(*mods, MODS_B_BIT1);
204     else
205 	CLR_BIT(*mods, MODS_B_BIT1);
206 }
207 
Get_laser_modifier(modifiers_t mods)208 static inline int Get_laser_modifier(modifiers_t mods)
209 {
210     int ls, lb;
211 
212     ls = BIT(mods, MODS_LS_BIT) ? 1 : 0;
213     lb = BIT(mods, MODS_LB_BIT) ? 1 : 0;
214 
215     return (lb << 1) + ls;
216 }
Set_laser_modifier(modifiers_t * mods,int value)217 static inline void Set_laser_modifier(modifiers_t *mods, int value)
218 {
219     LIMIT(value, 0, MODS_LASER_MAX);
220     if (BIT(value, MODS_BIT0))
221 	SET_BIT(*mods, MODS_LS_BIT);
222     else
223 	CLR_BIT(*mods, MODS_LS_BIT);
224     if (BIT(value, MODS_BIT1))
225 	SET_BIT(*mods, MODS_LB_BIT);
226     else
227 	CLR_BIT(*mods, MODS_LB_BIT);
228 }
229 
230 /*
231  * Returns 0 if ok, -1 if not allowed.
232  */
Mods_set(modifiers_t * mods,modifier_t modifier,int val)233 int Mods_set(modifiers_t *mods, modifier_t modifier, int val)
234 {
235     bool allow = false;
236 
237     if (val == 0)
238 	allow = true;
239     else if (modifier == ModsNuclear) {
240 	if (BIT(world->rules->mode, ALLOW_NUKES))
241 	    allow = true;
242     }
243     else if (modifier == ModsCluster) {
244 	if (BIT(world->rules->mode, ALLOW_CLUSTERS))
245 	    allow = true;
246     }
247     else if (modifier == ModsLaser) {
248 	if (BIT(world->rules->mode, ALLOW_LASER_MODIFIERS))
249 	    allow = true;
250     }
251     else {
252 	if (BIT(world->rules->mode, ALLOW_MODIFIERS))
253 	    allow = true;
254     }
255 
256     if (!allow)
257 	return -1;
258 
259     switch (modifier) {
260     case ModsNuclear:
261 	Set_nuclear_modifier(mods, val);
262 	break;
263     case ModsCluster:
264 	Set_cluster_modifier(mods, val);
265 	break;
266     case ModsImplosion:
267 	Set_implosion_modifier(mods, val);
268 	break;
269     case ModsVelocity:
270 	Set_velocity_modifier(mods, val);
271 	break;
272     case ModsMini:
273 	Set_mini_modifier(mods, val);
274 	break;
275     case ModsSpread:
276 	Set_spread_modifier(mods, val);
277 	break;
278     case ModsPower:
279 	Set_power_modifier(mods, val);
280 	break;
281     case ModsLaser:
282 	Set_laser_modifier(mods, val);
283 	break;
284     default:
285 	warn("No such modifier: %d", modifier);
286 	assert(0);
287 	break;
288     }
289 
290     return 0;
291 }
292 
Mods_get(modifiers_t mods,modifier_t modifier)293 int Mods_get(modifiers_t mods, modifier_t modifier)
294 {
295     switch (modifier) {
296     case ModsNuclear:
297 	return Get_nuclear_modifier(mods);
298     case ModsCluster:
299 	return Get_cluster_modifier(mods);
300     case ModsImplosion:
301 	return Get_implosion_modifier(mods);
302     case ModsVelocity:
303 	return Get_velocity_modifier(mods);
304     case ModsMini:
305 	return Get_mini_modifier(mods);
306     case ModsSpread:
307 	return Get_spread_modifier(mods);
308     case ModsPower:
309 	return Get_power_modifier(mods);
310     case ModsLaser:
311 	return Get_laser_modifier(mods);
312     default:
313 	assert(0);
314 	break;
315     }
316     return 0;
317 }
318 
319 /*
320  * modstr must be able to hold at least MAX_CHARS chars.
321  */
Mods_to_string(modifiers_t mods,char * modstr,size_t size)322 void Mods_to_string(modifiers_t mods, char *modstr, size_t size)
323 {
324     int i = 0, t;
325 
326     if (size < MAX_CHARS)
327 	return;
328     t = Get_nuclear_modifier(mods);
329     if (t & MODS_FULLNUCLEAR)
330 	modstr[i++] = 'F';
331     if (t & MODS_NUCLEAR)
332 	modstr[i++] = 'N';
333     if (Get_cluster_modifier(mods))
334 	modstr[i++] = 'C';
335     if (Get_implosion_modifier(mods))
336 	modstr[i++] = 'I';
337     t = Get_velocity_modifier(mods);
338     if (t) {
339 	if (i) modstr[i++] = ' ';
340 	modstr[i++] = 'V';
341 	i = num2str(t, modstr, i);
342     }
343     t = Get_mini_modifier(mods);
344     if (t) {
345 	if (i) modstr[i++] = ' ';
346 	modstr[i++] = 'X';
347 	i = num2str(t + 1, modstr, i);
348     }
349     t = Get_spread_modifier(mods);
350     if (t) {
351 	if (i) modstr[i++] = ' ';
352 	modstr[i++] = 'Z';
353 	i = num2str(t, modstr, i);
354     }
355     t = Get_power_modifier(mods);
356     if (t) {
357 	if (i) modstr[i++] = ' ';
358 	modstr[i++] = 'B';
359 	i = num2str(t, modstr, i);
360     }
361     t = Get_laser_modifier(mods);
362     if (t) {
363 	if (i) modstr[i++] = ' ';
364 	modstr[i++] = 'L';
365 	if (t & MODS_LASER_STUN)
366 	    modstr[i++] = 'S';
367 	if (t & MODS_LASER_BLIND)
368 	    modstr[i++] = 'B';
369     }
370     modstr[i] = '\0';
371 }
372 
373 
Mods_filter(modifiers_t * mods)374 void Mods_filter(modifiers_t *mods)
375 {
376     if (!BIT(world->rules->mode, ALLOW_NUKES))
377 	Mods_set(mods, ModsNuclear, 0);
378 
379     if (!BIT(world->rules->mode, ALLOW_CLUSTERS))
380 	Mods_set(mods, ModsCluster, 0);
381 
382     if (!BIT(world->rules->mode, ALLOW_MODIFIERS)) {
383 	Mods_set(mods, ModsImplosion, 0);
384 	Mods_set(mods, ModsVelocity, 0);
385 	Mods_set(mods, ModsMini, 0);
386 	Mods_set(mods, ModsSpread, 0);
387 	Mods_set(mods, ModsPower, 0);
388     }
389 
390     if (!BIT(world->rules->mode, ALLOW_LASER_MODIFIERS))
391 	Mods_set(mods, ModsLaser, 0);
392 }
393 
str2num(const char ** strp,int min,int max)394 static int str2num (const char **strp, int min, int max)
395 {
396     const char *str = *strp;
397     int num = 0;
398 
399     while (isdigit(*str)) {
400 	num *= 10;
401 	num += *str++ - '0';
402     }
403     *strp = str;
404     LIMIT(num, min, max);
405     return num;
406 }
407 
Player_set_modbank(player_t * pl,int bank,const char * str)408 void Player_set_modbank(player_t *pl, int bank, const char *str)
409 {
410     const char *cp;
411     modifiers_t mods;
412     int mini, velocity, spread, power;
413 
414     if (bank >= NUM_MODBANKS)
415 	return;
416 
417     Mods_clear(&mods);
418 
419     for (cp = str; *cp; cp++) {
420 	switch (*cp) {
421 	case 'F': case 'f':
422 	    if (*(cp+1) == 'N' || *(cp+1) == 'n')
423 		Mods_set(&mods, ModsNuclear,
424 			 MODS_NUCLEAR|MODS_FULLNUCLEAR);
425 	    break;
426 	case 'N': case 'n':
427 	    if (Mods_get(mods, ModsNuclear) == 0)
428 		Mods_set(&mods, ModsNuclear, MODS_NUCLEAR);
429 	    break;
430 	case 'C': case 'c':
431 	    Mods_set(&mods, ModsCluster, 1);
432 	    break;
433 	case 'I': case 'i':
434 	    Mods_set(&mods, ModsImplosion, 1);
435 	    break;
436 	case 'V': case 'v':
437 	    cp++;
438 	    velocity = str2num (&cp, 0, MODS_VELOCITY_MAX);
439 	    Mods_set(&mods, ModsVelocity, velocity);
440 	    cp--;
441 	    break;
442 	case 'X': case 'x':
443 	    cp++;
444 	    mini = str2num (&cp, 1, MODS_MINI_MAX+1) - 1;
445 	    Mods_set(&mods, ModsMini, mini);
446 	    cp--;
447 	    break;
448 	case 'Z': case 'z':
449 	    cp++;
450 	    spread = str2num (&cp, 0, MODS_SPREAD_MAX);
451 	    Mods_set(&mods, ModsSpread, spread);
452 	    cp--;
453 	    break;
454 	case 'B': case 'b':
455 	    cp++;
456 	    power = str2num (&cp, 0, MODS_POWER_MAX);
457 	    Mods_set(&mods, ModsPower, power);
458 	    cp--;
459 	    break;
460 	case 'L': case 'l':
461 	    cp++;
462 	    if (*cp == 'S' || *cp == 's')
463 		Mods_set(&mods, ModsLaser, MODS_LASER_STUN);
464 	    if (*cp == 'B' || *cp == 'b')
465 		Mods_set(&mods, ModsLaser, MODS_LASER_BLIND);
466 	    break;
467 	default:
468 	    /* Ignore unknown modifiers. */
469 	    break;
470 	}
471     }
472     pl->modbank[bank] = mods;
473 }
474