home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / g_spawn.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  14.6 KB  |  578 lines

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