g_spawn.c (16555B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 // 23 24 #include "g_local.h" 25 26 qboolean G_SpawnString( const char *key, const char *defaultString, char **out ) { 27 int i; 28 29 if ( !level.spawning ) { 30 *out = (char *)defaultString; 31 // G_Error( "G_SpawnString() called while not spawning" ); 32 } 33 34 for ( i = 0 ; i < level.numSpawnVars ; i++ ) { 35 if ( !Q_stricmp( key, level.spawnVars[i][0] ) ) { 36 *out = level.spawnVars[i][1]; 37 return qtrue; 38 } 39 } 40 41 *out = (char *)defaultString; 42 return qfalse; 43 } 44 45 qboolean G_SpawnFloat( const char *key, const char *defaultString, float *out ) { 46 char *s; 47 qboolean present; 48 49 present = G_SpawnString( key, defaultString, &s ); 50 *out = atof( s ); 51 return present; 52 } 53 54 qboolean G_SpawnInt( const char *key, const char *defaultString, int *out ) { 55 char *s; 56 qboolean present; 57 58 present = G_SpawnString( key, defaultString, &s ); 59 *out = atoi( s ); 60 return present; 61 } 62 63 qboolean G_SpawnVector( const char *key, const char *defaultString, float *out ) { 64 char *s; 65 qboolean present; 66 67 present = G_SpawnString( key, defaultString, &s ); 68 sscanf( s, "%f %f %f", &out[0], &out[1], &out[2] ); 69 return present; 70 } 71 72 73 74 // 75 // fields are needed for spawning from the entity string 76 // 77 typedef enum { 78 F_INT, 79 F_FLOAT, 80 F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL 81 F_GSTRING, // string on disk, pointer in memory, TAG_GAME 82 F_VECTOR, 83 F_ANGLEHACK, 84 F_ENTITY, // index on disk, pointer in memory 85 F_ITEM, // index on disk, pointer in memory 86 F_CLIENT, // index on disk, pointer in memory 87 F_IGNORE 88 } fieldtype_t; 89 90 typedef struct 91 { 92 char *name; 93 int ofs; 94 fieldtype_t type; 95 int flags; 96 } field_t; 97 98 field_t fields[] = { 99 {"classname", FOFS(classname), F_LSTRING}, 100 {"origin", FOFS(s.origin), F_VECTOR}, 101 {"model", FOFS(model), F_LSTRING}, 102 {"model2", FOFS(model2), F_LSTRING}, 103 {"spawnflags", FOFS(spawnflags), F_INT}, 104 {"speed", FOFS(speed), F_FLOAT}, 105 {"target", FOFS(target), F_LSTRING}, 106 {"targetname", FOFS(targetname), F_LSTRING}, 107 {"message", FOFS(message), F_LSTRING}, 108 {"team", FOFS(team), F_LSTRING}, 109 {"wait", FOFS(wait), F_FLOAT}, 110 {"random", FOFS(random), F_FLOAT}, 111 {"count", FOFS(count), F_INT}, 112 {"health", FOFS(health), F_INT}, 113 {"light", 0, F_IGNORE}, 114 {"dmg", FOFS(damage), F_INT}, 115 {"angles", FOFS(s.angles), F_VECTOR}, 116 {"angle", FOFS(s.angles), F_ANGLEHACK}, 117 {"targetShaderName", FOFS(targetShaderName), F_LSTRING}, 118 {"targetShaderNewName", FOFS(targetShaderNewName), F_LSTRING}, 119 120 {NULL} 121 }; 122 123 124 typedef struct { 125 char *name; 126 void (*spawn)(gentity_t *ent); 127 } spawn_t; 128 129 void SP_info_player_start (gentity_t *ent); 130 void SP_info_player_deathmatch (gentity_t *ent); 131 void SP_info_player_intermission (gentity_t *ent); 132 void SP_info_firstplace(gentity_t *ent); 133 void SP_info_secondplace(gentity_t *ent); 134 void SP_info_thirdplace(gentity_t *ent); 135 void SP_info_podium(gentity_t *ent); 136 137 void SP_func_plat (gentity_t *ent); 138 void SP_func_static (gentity_t *ent); 139 void SP_func_rotating (gentity_t *ent); 140 void SP_func_bobbing (gentity_t *ent); 141 void SP_func_pendulum( gentity_t *ent ); 142 void SP_func_button (gentity_t *ent); 143 void SP_func_door (gentity_t *ent); 144 void SP_func_train (gentity_t *ent); 145 void SP_func_timer (gentity_t *self); 146 147 void SP_trigger_always (gentity_t *ent); 148 void SP_trigger_multiple (gentity_t *ent); 149 void SP_trigger_push (gentity_t *ent); 150 void SP_trigger_teleport (gentity_t *ent); 151 void SP_trigger_hurt (gentity_t *ent); 152 153 void SP_target_remove_powerups( gentity_t *ent ); 154 void SP_target_give (gentity_t *ent); 155 void SP_target_delay (gentity_t *ent); 156 void SP_target_speaker (gentity_t *ent); 157 void SP_target_print (gentity_t *ent); 158 void SP_target_laser (gentity_t *self); 159 void SP_target_character (gentity_t *ent); 160 void SP_target_score( gentity_t *ent ); 161 void SP_target_teleporter( gentity_t *ent ); 162 void SP_target_relay (gentity_t *ent); 163 void SP_target_kill (gentity_t *ent); 164 void SP_target_position (gentity_t *ent); 165 void SP_target_location (gentity_t *ent); 166 void SP_target_push (gentity_t *ent); 167 168 void SP_light (gentity_t *self); 169 void SP_info_null (gentity_t *self); 170 void SP_info_notnull (gentity_t *self); 171 void SP_info_camp (gentity_t *self); 172 void SP_path_corner (gentity_t *self); 173 174 void SP_misc_teleporter_dest (gentity_t *self); 175 void SP_misc_model(gentity_t *ent); 176 void SP_misc_portal_camera(gentity_t *ent); 177 void SP_misc_portal_surface(gentity_t *ent); 178 179 void SP_shooter_rocket( gentity_t *ent ); 180 void SP_shooter_plasma( gentity_t *ent ); 181 void SP_shooter_grenade( gentity_t *ent ); 182 183 void SP_team_CTF_redplayer( gentity_t *ent ); 184 void SP_team_CTF_blueplayer( gentity_t *ent ); 185 186 void SP_team_CTF_redspawn( gentity_t *ent ); 187 void SP_team_CTF_bluespawn( gentity_t *ent ); 188 189 #ifdef MISSIONPACK 190 void SP_team_blueobelisk( gentity_t *ent ); 191 void SP_team_redobelisk( gentity_t *ent ); 192 void SP_team_neutralobelisk( gentity_t *ent ); 193 #endif 194 void SP_item_botroam( gentity_t *ent ) {}; 195 196 spawn_t spawns[] = { 197 // info entities don't do anything at all, but provide positional 198 // information for things controlled by other processes 199 {"info_player_start", SP_info_player_start}, 200 {"info_player_deathmatch", SP_info_player_deathmatch}, 201 {"info_player_intermission", SP_info_player_intermission}, 202 {"info_null", SP_info_null}, 203 {"info_notnull", SP_info_notnull}, // use target_position instead 204 {"info_camp", SP_info_camp}, 205 206 {"func_plat", SP_func_plat}, 207 {"func_button", SP_func_button}, 208 {"func_door", SP_func_door}, 209 {"func_static", SP_func_static}, 210 {"func_rotating", SP_func_rotating}, 211 {"func_bobbing", SP_func_bobbing}, 212 {"func_pendulum", SP_func_pendulum}, 213 {"func_train", SP_func_train}, 214 {"func_group", SP_info_null}, 215 {"func_timer", SP_func_timer}, // rename trigger_timer? 216 217 // Triggers are brush objects that cause an effect when contacted 218 // by a living player, usually involving firing targets. 219 // While almost everything could be done with 220 // a single trigger class and different targets, triggered effects 221 // could not be client side predicted (push and teleport). 222 {"trigger_always", SP_trigger_always}, 223 {"trigger_multiple", SP_trigger_multiple}, 224 {"trigger_push", SP_trigger_push}, 225 {"trigger_teleport", SP_trigger_teleport}, 226 {"trigger_hurt", SP_trigger_hurt}, 227 228 // targets perform no action by themselves, but must be triggered 229 // by another entity 230 {"target_give", SP_target_give}, 231 {"target_remove_powerups", SP_target_remove_powerups}, 232 {"target_delay", SP_target_delay}, 233 {"target_speaker", SP_target_speaker}, 234 {"target_print", SP_target_print}, 235 {"target_laser", SP_target_laser}, 236 {"target_score", SP_target_score}, 237 {"target_teleporter", SP_target_teleporter}, 238 {"target_relay", SP_target_relay}, 239 {"target_kill", SP_target_kill}, 240 {"target_position", SP_target_position}, 241 {"target_location", SP_target_location}, 242 {"target_push", SP_target_push}, 243 244 {"light", SP_light}, 245 {"path_corner", SP_path_corner}, 246 247 {"misc_teleporter_dest", SP_misc_teleporter_dest}, 248 {"misc_model", SP_misc_model}, 249 {"misc_portal_surface", SP_misc_portal_surface}, 250 {"misc_portal_camera", SP_misc_portal_camera}, 251 252 {"shooter_rocket", SP_shooter_rocket}, 253 {"shooter_grenade", SP_shooter_grenade}, 254 {"shooter_plasma", SP_shooter_plasma}, 255 256 {"team_CTF_redplayer", SP_team_CTF_redplayer}, 257 {"team_CTF_blueplayer", SP_team_CTF_blueplayer}, 258 259 {"team_CTF_redspawn", SP_team_CTF_redspawn}, 260 {"team_CTF_bluespawn", SP_team_CTF_bluespawn}, 261 262 #ifdef MISSIONPACK 263 {"team_redobelisk", SP_team_redobelisk}, 264 {"team_blueobelisk", SP_team_blueobelisk}, 265 {"team_neutralobelisk", SP_team_neutralobelisk}, 266 #endif 267 {"item_botroam", SP_item_botroam}, 268 269 {0, 0} 270 }; 271 272 /* 273 =============== 274 G_CallSpawn 275 276 Finds the spawn function for the entity and calls it, 277 returning qfalse if not found 278 =============== 279 */ 280 qboolean G_CallSpawn( gentity_t *ent ) { 281 spawn_t *s; 282 gitem_t *item; 283 284 if ( !ent->classname ) { 285 G_Printf ("G_CallSpawn: NULL classname\n"); 286 return qfalse; 287 } 288 289 // check item spawn functions 290 for ( item=bg_itemlist+1 ; item->classname ; item++ ) { 291 if ( !strcmp(item->classname, ent->classname) ) { 292 G_SpawnItem( ent, item ); 293 return qtrue; 294 } 295 } 296 297 // check normal spawn functions 298 for ( s=spawns ; s->name ; s++ ) { 299 if ( !strcmp(s->name, ent->classname) ) { 300 // found it 301 s->spawn(ent); 302 return qtrue; 303 } 304 } 305 G_Printf ("%s doesn't have a spawn function\n", ent->classname); 306 return qfalse; 307 } 308 309 /* 310 ============= 311 G_NewString 312 313 Builds a copy of the string, translating \n to real linefeeds 314 so message texts can be multi-line 315 ============= 316 */ 317 char *G_NewString( const char *string ) { 318 char *newb, *new_p; 319 int i,l; 320 321 l = strlen(string) + 1; 322 323 newb = G_Alloc( l ); 324 325 new_p = newb; 326 327 // turn \n into a real linefeed 328 for ( i=0 ; i< l ; i++ ) { 329 if (string[i] == '\\' && i < l-1) { 330 i++; 331 if (string[i] == 'n') { 332 *new_p++ = '\n'; 333 } else { 334 *new_p++ = '\\'; 335 } 336 } else { 337 *new_p++ = string[i]; 338 } 339 } 340 341 return newb; 342 } 343 344 345 346 347 /* 348 =============== 349 G_ParseField 350 351 Takes a key/value pair and sets the binary values 352 in a gentity 353 =============== 354 */ 355 void G_ParseField( const char *key, const char *value, gentity_t *ent ) { 356 field_t *f; 357 byte *b; 358 float v; 359 vec3_t vec; 360 361 for ( f=fields ; f->name ; f++ ) { 362 if ( !Q_stricmp(f->name, key) ) { 363 // found it 364 b = (byte *)ent; 365 366 switch( f->type ) { 367 case F_LSTRING: 368 *(char **)(b+f->ofs) = G_NewString (value); 369 break; 370 case F_VECTOR: 371 sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]); 372 ((float *)(b+f->ofs))[0] = vec[0]; 373 ((float *)(b+f->ofs))[1] = vec[1]; 374 ((float *)(b+f->ofs))[2] = vec[2]; 375 break; 376 case F_INT: 377 *(int *)(b+f->ofs) = atoi(value); 378 break; 379 case F_FLOAT: 380 *(float *)(b+f->ofs) = atof(value); 381 break; 382 case F_ANGLEHACK: 383 v = atof(value); 384 ((float *)(b+f->ofs))[0] = 0; 385 ((float *)(b+f->ofs))[1] = v; 386 ((float *)(b+f->ofs))[2] = 0; 387 break; 388 default: 389 case F_IGNORE: 390 break; 391 } 392 return; 393 } 394 } 395 } 396 397 398 399 400 /* 401 =================== 402 G_SpawnGEntityFromSpawnVars 403 404 Spawn an entity and fill in all of the level fields from 405 level.spawnVars[], then call the class specfic spawn function 406 =================== 407 */ 408 void G_SpawnGEntityFromSpawnVars( void ) { 409 int i; 410 gentity_t *ent; 411 char *s, *value, *gametypeName; 412 static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester", "teamtournament"}; 413 414 // get the next free entity 415 ent = G_Spawn(); 416 417 for ( i = 0 ; i < level.numSpawnVars ; i++ ) { 418 G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent ); 419 } 420 421 // check for "notsingle" flag 422 if ( g_gametype.integer == GT_SINGLE_PLAYER ) { 423 G_SpawnInt( "notsingle", "0", &i ); 424 if ( i ) { 425 G_FreeEntity( ent ); 426 return; 427 } 428 } 429 // check for "notteam" flag (GT_FFA, GT_TOURNAMENT, GT_SINGLE_PLAYER) 430 if ( g_gametype.integer >= GT_TEAM ) { 431 G_SpawnInt( "notteam", "0", &i ); 432 if ( i ) { 433 G_FreeEntity( ent ); 434 return; 435 } 436 } else { 437 G_SpawnInt( "notfree", "0", &i ); 438 if ( i ) { 439 G_FreeEntity( ent ); 440 return; 441 } 442 } 443 444 #ifdef MISSIONPACK 445 G_SpawnInt( "notta", "0", &i ); 446 if ( i ) { 447 G_FreeEntity( ent ); 448 return; 449 } 450 #else 451 G_SpawnInt( "notq3a", "0", &i ); 452 if ( i ) { 453 G_FreeEntity( ent ); 454 return; 455 } 456 #endif 457 458 if( G_SpawnString( "gametype", NULL, &value ) ) { 459 if( g_gametype.integer >= GT_FFA && g_gametype.integer < GT_MAX_GAME_TYPE ) { 460 gametypeName = gametypeNames[g_gametype.integer]; 461 462 s = strstr( value, gametypeName ); 463 if( !s ) { 464 G_FreeEntity( ent ); 465 return; 466 } 467 } 468 } 469 470 // move editor origin to pos 471 VectorCopy( ent->s.origin, ent->s.pos.trBase ); 472 VectorCopy( ent->s.origin, ent->r.currentOrigin ); 473 474 // if we didn't get a classname, don't bother spawning anything 475 if ( !G_CallSpawn( ent ) ) { 476 G_FreeEntity( ent ); 477 } 478 } 479 480 481 482 /* 483 ==================== 484 G_AddSpawnVarToken 485 ==================== 486 */ 487 char *G_AddSpawnVarToken( const char *string ) { 488 int l; 489 char *dest; 490 491 l = strlen( string ); 492 if ( level.numSpawnVarChars + l + 1 > MAX_SPAWN_VARS_CHARS ) { 493 G_Error( "G_AddSpawnVarToken: MAX_SPAWN_CHARS" ); 494 } 495 496 dest = level.spawnVarChars + level.numSpawnVarChars; 497 memcpy( dest, string, l+1 ); 498 499 level.numSpawnVarChars += l + 1; 500 501 return dest; 502 } 503 504 /* 505 ==================== 506 G_ParseSpawnVars 507 508 Parses a brace bounded set of key / value pairs out of the 509 level's entity strings into level.spawnVars[] 510 511 This does not actually spawn an entity. 512 ==================== 513 */ 514 qboolean G_ParseSpawnVars( void ) { 515 char keyname[MAX_TOKEN_CHARS]; 516 char com_token[MAX_TOKEN_CHARS]; 517 518 level.numSpawnVars = 0; 519 level.numSpawnVarChars = 0; 520 521 // parse the opening brace 522 if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) { 523 // end of spawn string 524 return qfalse; 525 } 526 if ( com_token[0] != '{' ) { 527 G_Error( "G_ParseSpawnVars: found %s when expecting {",com_token ); 528 } 529 530 // go through all the key / value pairs 531 while ( 1 ) { 532 // parse key 533 if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) { 534 G_Error( "G_ParseSpawnVars: EOF without closing brace" ); 535 } 536 537 if ( keyname[0] == '}' ) { 538 break; 539 } 540 541 // parse value 542 if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) { 543 G_Error( "G_ParseSpawnVars: EOF without closing brace" ); 544 } 545 546 if ( com_token[0] == '}' ) { 547 G_Error( "G_ParseSpawnVars: closing brace without data" ); 548 } 549 if ( level.numSpawnVars == MAX_SPAWN_VARS ) { 550 G_Error( "G_ParseSpawnVars: MAX_SPAWN_VARS" ); 551 } 552 level.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( keyname ); 553 level.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( com_token ); 554 level.numSpawnVars++; 555 } 556 557 return qtrue; 558 } 559 560 561 562 /*QUAKED worldspawn (0 0 0) ? 563 564 Every map should have exactly one worldspawn. 565 "music" music wav file 566 "gravity" 800 is default gravity 567 "message" Text to print during connection process 568 */ 569 void SP_worldspawn( void ) { 570 char *s; 571 572 G_SpawnString( "classname", "", &s ); 573 if ( Q_stricmp( s, "worldspawn" ) ) { 574 G_Error( "SP_worldspawn: The first entity isn't 'worldspawn'" ); 575 } 576 577 // make some data visible to connecting client 578 trap_SetConfigstring( CS_GAME_VERSION, GAME_VERSION ); 579 580 trap_SetConfigstring( CS_LEVEL_START_TIME, va("%i", level.startTime ) ); 581 582 G_SpawnString( "music", "", &s ); 583 trap_SetConfigstring( CS_MUSIC, s ); 584 585 G_SpawnString( "message", "", &s ); 586 trap_SetConfigstring( CS_MESSAGE, s ); // map specific message 587 588 trap_SetConfigstring( CS_MOTD, g_motd.string ); // message of the day 589 590 G_SpawnString( "gravity", "800", &s ); 591 trap_Cvar_Set( "g_gravity", s ); 592 593 G_SpawnString( "enableDust", "0", &s ); 594 trap_Cvar_Set( "g_enableDust", s ); 595 596 G_SpawnString( "enableBreath", "0", &s ); 597 trap_Cvar_Set( "g_enableBreath", s ); 598 599 g_entities[ENTITYNUM_WORLD].s.number = ENTITYNUM_WORLD; 600 g_entities[ENTITYNUM_WORLD].classname = "worldspawn"; 601 602 // see if we want a warmup time 603 trap_SetConfigstring( CS_WARMUP, "" ); 604 if ( g_restarted.integer ) { 605 trap_Cvar_Set( "g_restarted", "0" ); 606 level.warmupTime = 0; 607 } else if ( g_doWarmup.integer ) { // Turn it on 608 level.warmupTime = -1; 609 trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) ); 610 G_LogPrintf( "Warmup:\n" ); 611 } 612 613 } 614 615 616 /* 617 ============== 618 G_SpawnEntitiesFromString 619 620 Parses textual entity definitions out of an entstring and spawns gentities. 621 ============== 622 */ 623 void G_SpawnEntitiesFromString( void ) { 624 // allow calls to G_Spawn*() 625 level.spawning = qtrue; 626 level.numSpawnVars = 0; 627 628 // the worldspawn is not an actual entity, but it still 629 // has a "spawn" function to perform any global setup 630 // needed by a level (setting configstrings or cvars, etc) 631 if ( !G_ParseSpawnVars() ) { 632 G_Error( "SpawnEntities: no entities" ); 633 } 634 SP_worldspawn(); 635 636 // parse ents 637 while( G_ParseSpawnVars() ) { 638 G_SpawnGEntityFromSpawnVars(); 639 } 640 641 level.spawning = qfalse; // any future calls to G_Spawn*() will be errors 642 } 643