aboutsummaryrefslogtreecommitdiff
path: root/src/libparsec/obj_creg.cpp
blob: 62b12660c71ea40acefd071755b7e74034c1aad1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
/*
 * PARSEC - Object Class Registration
 *
 * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:44 $
 *
 * Orginally written by:
 *   Copyright (c) Markus Hadwiger     <msh@parsec.org>   1999
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */ 

// C library
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// compilation flags/debug support
#include "config.h"
#include "debug.h"

// general definitions
#include "general.h"
#include "objstruc.h"
#include "od_class.h"

// global externals
#include "globals.h"
#ifdef PARSEC_SERVER
	#include "e_world_trans.h"
#endif // PARSEC_SERVER

// local module header
#include "obj_creg.h"

// proprietary module headers
#include "con_arg.h"
#ifdef PARSEC_SERVER
	#include "con_com_sv.h"
	#include "con_main_sv.h"
#else // !PARSEC_SERVER
	#include "con_com.h"
	#include "con_main.h"
	#include "e_supp.h"
#endif // !PARSEC_SERVER
#include "obj_clas.h"



// string constants -----------------------------------------------------------
//
static char intlist_invalid[]		= "intlist invalid.";
static char no_ship_class[]			= "object class is no ship.";
static char too_many_ships[]		= "no more ships allowed.";
static char no_extra_class[]		= "object class is no extra.";
static char too_many_extras[]		= "no more extras allowed.";
static char invalid_texture[]		= "invalid texture specified.";


// class registration entry ---------------------------------------------------
//
struct classregfunc_s {

	classreg_fpt	regfunc;
	classregfunc_s	*next;
};

classregfunc_s *classregfunc_list = NULL;


// register class-registration callback ---------------------------------------
//
int OBJ_RegisterClassRegistration( classreg_fpt regfunc )
{
	ASSERT( regfunc != NULL );

	//NOTE:
	// registration callback functions must be idempotent.
	// (they may be called multiple times, but semantics
	// equivalent to call-once must be guaranteed.)

	classregfunc_s *newregfunc = (classregfunc_s *) ALLOCMEM( sizeof( classregfunc_s ) );
	if ( newregfunc == NULL ) {
		ASSERT( 0 );
		return FALSE;
	}

	// prepend to list
	newregfunc->regfunc	= regfunc;
	newregfunc->next	= classregfunc_list;
	classregfunc_list	= newregfunc;

	return TRUE;
}


// key table for do_creg command ----------------------------------------------
//
key_value_s do_creg_key_value[] = {

	{ "intlist",	NULL,	KEYVALFLAG_PARENTHESIZE		},

	{ NULL,			NULL,	KEYVALFLAG_NONE				},
};

enum {

	KEY_DO_CREG_INTLIST
};


// console command for registering all pending classes ("do_creg") ------------
//
PRIVATE
int Cmd_DO_CREG( char *intliststr )
{
	//NOTE:
	//CONCOM:
	// do_creg_command	::= 'do_creg' [<int_list>]
	// int_list			::= <int> [<int_list>]

	ASSERT( intliststr != NULL );
	HANDLE_COMMAND_DOMAIN_SEP( intliststr );

	// scan out all values to keys
	if ( !ScanKeyValuePairs( do_creg_key_value, intliststr ) )
		return TRUE;

	#define MAX_INTLIST_LENGTH 16
	int intlist[ MAX_INTLIST_LENGTH ];
	int numints	= 0;

	// try to read optional int list
	if ( do_creg_key_value[ KEY_DO_CREG_INTLIST ].value != NULL ) {
		numints = ScanKeyValueIntList( &do_creg_key_value[ KEY_DO_CREG_INTLIST ], intlist, 1, MAX_INTLIST_LENGTH );
		if ( numints < 1 ) {
			CON_AddLine( intlist_invalid );
			return TRUE;
		}
	}

	// call all registered functions
	for ( classregfunc_s *scan = classregfunc_list; scan; scan = scan->next ) {
		ASSERT( scan->regfunc != NULL );
		(*scan->regfunc)( numints, intlist );
	}

	return TRUE;
}


// global ship class table ----------------------------------------------------
//
dword ShipClasses[ MAX_SHIP_CLASSES ] = {

	SHIP_CLASS_1,	// shipclassid 00: firebird
	SHIP_CLASS_3,	// shipclassid 01: bluespire
	SHIP_CLASS_2,	// shipclassid 02: cormoran
};

int NumShipClasses = 3; //CALC_NUM_ARRAY_ENTRIES( ShipClasses );


// reverse lookup ship class table --------------------------------------------
//
int ObjClassShipIndex[ MAX_DISTINCT_OBJCLASSES ];


// register a new ship class --------------------------------------------------
//
int OBJ_RegisterShipClass( dword classid )
{
	ASSERT( classid < (dword)NumObjClasses );
	ASSERT( OBJECT_TYPE_SHIP( ObjClasses[ classid ] ) );

	if ( NumShipClasses >= MAX_SHIP_CLASSES ) {
		return FALSE;
	}

	// turn specified class into a ship class
	ShipClasses[ NumShipClasses ]	= classid;
	ObjClassShipIndex[ classid ]	= NumShipClasses;

	NumShipClasses++;

	return TRUE;
}


// key table for shipclass command --------------------------------------------
//
key_value_s shipclass_key_value[] = {

	{ "class",		NULL,	KEYVALFLAG_PARENTHESIZE		},
	{ "id",			NULL,	KEYVALFLAG_NONE				},
	{ "texture",	NULL,	KEYVALFLAG_PARENTHESIZE		},

	{ NULL,			NULL,	KEYVALFLAG_NONE				},
};

enum {

	KEY_SHIPCLASS_CLASS,
	KEY_SHIPCLASS_ID,
	KEY_SHIPCLASS_TEXTURE
};


// console command for registering a new ship class ("shipclass") -------------
//
PRIVATE
int Cmd_SHIPCLASS( char *classstr )
{
	//NOTE:
	//CONCOM:
	// shipclass_command	::= 'shipclass' <class_spec> [<monitor_texture_spec>]
	// class_spec			::= 'class' <classname> | 'id' <classid>
	// monitor_texture_spec ::= 'texture' <texturename>

	ASSERT( classstr != NULL );
	HANDLE_COMMAND_DOMAIN_SEP( classstr );

	// scan out all values to keys
	if ( !ScanKeyValuePairs( shipclass_key_value, classstr ) )
		return TRUE;

	// get object class (either name or id)
	dword objclass = ScanKeyValueObjClass( shipclass_key_value, KEY_SHIPCLASS_CLASS, KEY_SHIPCLASS_ID );
	if ( objclass == CLASS_ID_INVALID ) {
		return TRUE;
	}

	if ( !OBJECT_TYPE_SHIP( ObjClasses[ objclass ] ) ) {
		CON_AddLine( no_ship_class );
		return TRUE;
	}

	if ( NumShipClasses >= MAX_SHIP_CLASSES ) {
		CON_AddLine( too_many_ships );
		return TRUE;
	}

	// check if class is already registered
	int firstreg = TRUE;
	char *classname = shipclass_key_value[ KEY_SHIPCLASS_CLASS ].value;
	ASSERT( ( classname == NULL ) || ( stricmp( classname, ObjectInfo[ objclass ].name ) == 0 ) );
	classname = ObjectInfo[ objclass ].name;

	for ( int sid = 0; sid < NumShipClasses; sid++ ) {
		if ( strcmp( classname, ObjectInfo[ ShipClasses[ sid ] ].name ) == 0 ) {
			firstreg = FALSE;
			break;
		}
	}

	// turn specified class into a ship class
	if ( firstreg ) {
		ShipClasses[ NumShipClasses ] = objclass;
		ObjClassShipIndex[ objclass ] = NumShipClasses;
		NumShipClasses++;
	}

#ifdef PARSEC_CLIENT

	// check for shipmonitor texture name and save
	// texturemap pointer for use in H_COCKPT.C
	char *texturename = shipclass_key_value[ KEY_SHIPCLASS_TEXTURE ].value;
	if ( texturename != NULL ) {
		TextureMap *texmap = FetchTextureMap( texturename );
		if ( texmap != NULL ) {
			extern TextureMap *MonitorTextures[];
			MonitorTextures[ ObjClassShipIndex[ objclass ] ] = texmap;
		} else {
			CON_AddLine( invalid_texture );
			return TRUE;
		}
	}

#endif // PARSEC_CLIENT

	return TRUE;
}


// global extra class table ---------------------------------------------------
//
dword ExtraClasses[ MAX_EXTRA_CLASSES ] = {

	ENERGY_EXTRA_CLASS,			// extra classindex 00: energy boost
	DUMB_PACK_CLASS,			// extra classindex 01: missile pack (dumb missiles)
	GUIDE_PACK_CLASS,			// extra classindex 02: missile pack (guided missiles)
	HELIX_DEVICE_CLASS,			// extra classindex 03: dazzling laser/helix cannon
	LIGHTNING_DEVICE_CLASS,		// extra classindex 04: thief laser/lightning device
	MINE_PACK_CLASS,			// extra classindex 05: mine pack (proximity mines)
	REPAIR_EXTRA_CLASS,			// extra classindex 06: repair damage
	AFTERBURNER_DEVICE_CLASS,	// extra classindex 07: afterburner
	SWARM_PACK_CLASS,			// extra classindex 08: missile pack (swarm missiles)
	INVISIBILITY_CLASS,			// extra classindex 09: invisibility (not used yet)
	PHOTON_DEVICE_CLASS,		// extra classindex 10: photon cannon
	DECOY_DEVICE_CLASS,			// extra classindex 11: decoy device
	LASERUPGRADE1_CLASS,		// extra classindex 12: laser upgrade 1
	LASERUPGRADE2_CLASS,		// extra classindex 13: laser upgrade 2
	INVULNERABILITY_CLASS,		// extra classindex 14: invulnerability
	MINE_CLASS_1,				// extra classindex 15: mine
	CLASS_ID_INVALID,			// extra classindex 16: emp upgrade 1
	CLASS_ID_INVALID,			// extra classindex 17: emp upgrade 2
};

int NumExtraClasses = 16; //CALC_NUM_ARRAY_ENTRIES( ExtraClasses );


// reverse lookup extra class table -------------------------------------------
//
int ObjClassExtraIndex[ MAX_DISTINCT_OBJCLASSES ];


// register a new extra class -------------------------------------------------
//
int OBJ_RegisterExtraClass( int index, dword classid )
{
	ASSERT( classid < (dword)NumObjClasses );
	ASSERT( OBJECT_TYPE_EXTRA( ObjClasses[ classid ] ) );

	if ( index < NumExtraClasses ) {

	} else {

		if ( NumExtraClasses >= MAX_EXTRA_CLASSES ) {
			return FALSE;
		}

		// turn specified class into an extra class
		ExtraClasses[ NumExtraClasses ]	= classid;
		ObjClassExtraIndex[ classid ]   = NumExtraClasses;

		NumExtraClasses++;
	}

	return TRUE;
}


// key table for extraclass command -------------------------------------------
//
key_value_s extraclass_key_value[] = {

	{ "class",		NULL,	KEYVALFLAG_PARENTHESIZE		},
	{ "id",			NULL,	KEYVALFLAG_NONE				},

	{ NULL,			NULL,	KEYVALFLAG_NONE				},
};

enum {

	KEY_EXTRACLASS_CLASS,
	KEY_EXTRACLASS_ID
};


// console command for registering a new extra class ("extraclass") -----------
//
PRIVATE
int Cmd_EXTRACLASS( char *classstr )
{
	//NOTE:
	//CONCOM:
	// extraclass_command	::= 'extraclass' <class_spec>
	// class_spec			::= 'class' <classname> | 'id' <classid>

	ASSERT( classstr != NULL );
	HANDLE_COMMAND_DOMAIN_SEP( classstr );

	// scan out all values to keys
	if ( !ScanKeyValuePairs( extraclass_key_value, classstr ) )
		return TRUE;

	// get object class (either name or id)
	dword objclass = ScanKeyValueObjClass( extraclass_key_value, KEY_EXTRACLASS_CLASS, KEY_EXTRACLASS_ID );
	if ( objclass == CLASS_ID_INVALID ) {
		return TRUE;
	}

	if ( !OBJECT_TYPE_EXTRA( ObjClasses[ objclass ] ) ) {
		CON_AddLine( no_extra_class );
		return TRUE;
	}

	if ( NumExtraClasses >= MAX_EXTRA_CLASSES ) {
		CON_AddLine( too_many_extras );
		return TRUE;
	}

	// turn specified class into an extra class
	OBJ_RegisterExtraClass( NumExtraClasses, objclass );

	return TRUE;
}


// module registration function -----------------------------------------------
//
REGISTER_MODULE( OBJ_CREG )
{
	user_command_s regcom;
	memset( &regcom, 0, sizeof( user_command_s ) );

	// register "do_creg" command
	regcom.command	 = "do_creg";
	regcom.numparams = 1;
	regcom.execute	 = Cmd_DO_CREG;
	regcom.statedump = NULL;
	CON_RegisterUserCommand( &regcom );

	// register "shipclass" command
	regcom.command	 = "shipclass";
	regcom.numparams = 1;
	regcom.execute	 = Cmd_SHIPCLASS;
	regcom.statedump = NULL;
	CON_RegisterUserCommand( &regcom );

	// init reverse lookup of ship classes
	unsigned int cid = 0;
	for ( cid = 0; cid < MAX_DISTINCT_OBJCLASSES; cid++ ) {
		ObjClassShipIndex[ cid ] = SHIPINDEX_NO_SHIP;
		for ( int scid = 0; scid < NumShipClasses; scid++ ) {
			if ( ShipClasses[ scid ] == cid ) {
				ObjClassShipIndex[ cid ] =  scid;
				break;
			}
		}
	}

	// register "extraclass" command
	regcom.command	 = "extraclass";
	regcom.numparams = 1;
	regcom.execute	 = Cmd_EXTRACLASS;
	regcom.statedump = NULL;
	CON_RegisterUserCommand( &regcom );

	// init reverse lookup of extra classes
	for ( cid = 0; cid < MAX_DISTINCT_OBJCLASSES; cid++ ) {
		ObjClassExtraIndex[ cid ] = EXTRAINDEX_NO_EXTRA;
		for ( unsigned int ecid = 0; ecid < (dword)NumExtraClasses; ecid++ ) {
			if ( ExtraClasses[ ecid ] == cid ) {
				ObjClassExtraIndex[ cid ] =  ecid;
				break;
			}
		}
	}
}