cl_sequence.c

Go to the documentation of this file.
00001 
00008 /*
00009 Copyright (C) 2002-2010 UFO: Alien Invasion.
00010 
00011 This program is free software; you can redistribute it and/or
00012 modify it under the terms of the GNU General Public License
00013 as published by the Free Software Foundation; either version 2
00014 of the License, or (at your option) any later version.
00015 
00016 This program is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00019 
00020 See the GNU General Public License for more details.
00021 
00022 You should have received a copy of the GNU General Public License
00023 along with this program; if not, write to the Free Software
00024 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00025 
00026 */
00027 
00028 #include "client.h"
00029 #include "cl_sequence.h"
00030 #include "battlescape/cl_localentity.h"
00031 #include "battlescape/cl_view.h"
00032 #include "renderer/r_main.h"
00033 #include "renderer/r_draw.h"
00034 #include "renderer/r_mesh_anim.h"
00035 #include "../shared/parse.h"
00036 #include "ui/ui_main.h"
00037 #include "ui/ui_nodes.h"
00038 #include "ui/ui_render.h"
00039 
00040 #define MAX_DATA_LENGTH 2048
00041 
00042 struct sequenceContext_s;
00043 
00048 typedef int (*sequenceHandler_t) (struct sequenceContext_s *context, const char *name, const char *data);
00049 
00050 typedef struct seqCmd_s {
00051     sequenceHandler_t handler;
00052     char name[MAX_VAR];
00053     char data[MAX_DATA_LENGTH];
00054 } seqCmd_t;
00055 
00056 typedef struct sequence_s {
00057     char name[MAX_VAR]; 
00058     int start;      
00059     int length;     
00060 } sequence_t;
00061 
00062 typedef struct seqCamera_s {
00063     vec3_t origin;
00064     vec3_t speed;
00065     vec3_t angles;
00066     vec3_t omega;
00067     float dist;     
00068     float ddist;    
00069     float zoom;     
00070     float dzoom;    
00071 } seqCamera_t;
00072 
00076 typedef struct seqEnt_s {
00077     qboolean inuse;
00078     char name[MAX_VAR];
00079     model_t *model;     
00080     int skin;           
00081     vec3_t origin;      
00082     vec3_t speed;       
00083     vec3_t angles;      
00084     vec3_t omega;       
00085     vec3_t color;
00086     float alpha;
00087     char parent[MAX_VAR];   
00088     char tag[MAX_VAR];      
00089     animState_t as;         
00090     entity_t *ep;
00091 } seqEnt_t;
00092 
00096 typedef struct seq2D_s {
00097     qboolean inuse;         
00098     char name[MAX_VAR];     
00099     char *text;             
00100     char font[MAX_VAR];     
00101     char image[MAX_VAR];    
00102     vec2_t pos;         
00103     vec2_t speed;       
00104     vec2_t size;        
00105     vec2_t enlarge;     
00106     vec4_t color;       
00107     vec4_t fade;        
00108     vec4_t bgcolor;     
00109     align_t align;      
00110     qboolean relativePos;   
00111 } seq2D_t;
00112 
00113 #define MAX_SEQCMDS     8192
00114 #define MAX_SEQUENCES   32
00115 #define MAX_SEQENTS     128
00116 #define MAX_SEQ2DS      128
00117 
00122 static sequence_t sequences[MAX_SEQUENCES];
00123 static int numSequences;
00124 
00126 static seqCmd_t seqCmds[MAX_SEQCMDS];
00127 static int numSeqCmds;
00128 
00131 typedef struct sequenceContext_s {
00133     int time;
00135     qboolean endClickLoop;
00137     int currentCmd;
00139     int endCmd;
00141     cvar_t *animspeed;
00142 
00144     seqCamera_t camera;
00145 
00147     seqEnt_t ents[MAX_SEQENTS];
00148     int numEnts;
00149 
00151     seq2D_t obj2Ds[MAX_SEQ2DS];
00152     int numObj2Ds;
00153 
00154 } sequenceContext_t;
00155 
00157 static const value_t seqCamera_vals[] = {
00158     {"origin", V_VECTOR, offsetof(seqCamera_t, origin), MEMBER_SIZEOF(seqCamera_t, origin)},
00159     {"speed", V_VECTOR, offsetof(seqCamera_t, speed), MEMBER_SIZEOF(seqCamera_t, speed)},
00160     {"angles", V_VECTOR, offsetof(seqCamera_t, angles), MEMBER_SIZEOF(seqCamera_t, angles)},
00161     {"omega", V_VECTOR, offsetof(seqCamera_t, omega), MEMBER_SIZEOF(seqCamera_t, omega)},
00162     {"dist", V_FLOAT, offsetof(seqCamera_t, dist), MEMBER_SIZEOF(seqCamera_t, dist)},
00163     {"ddist", V_FLOAT, offsetof(seqCamera_t, ddist), MEMBER_SIZEOF(seqCamera_t, ddist)},
00164     {"zoom", V_FLOAT, offsetof(seqCamera_t, zoom), MEMBER_SIZEOF(seqCamera_t, zoom)},
00165     {"dzoom", V_FLOAT, offsetof(seqCamera_t, dzoom), MEMBER_SIZEOF(seqCamera_t, dzoom)},
00166     {NULL, 0, 0, 0}
00167 };
00168 
00170 static const value_t seqEnt_vals[] = {
00171     {"name", V_STRING, offsetof(seqEnt_t, name), 0},
00172     {"skin", V_INT, offsetof(seqEnt_t, skin), MEMBER_SIZEOF(seqEnt_t, skin)},
00173     {"alpha", V_FLOAT, offsetof(seqEnt_t, alpha), MEMBER_SIZEOF(seqEnt_t, alpha)},
00174     {"origin", V_VECTOR, offsetof(seqEnt_t, origin), MEMBER_SIZEOF(seqEnt_t, origin)},
00175     {"speed", V_VECTOR, offsetof(seqEnt_t, speed), MEMBER_SIZEOF(seqEnt_t, speed)},
00176     {"angles", V_VECTOR, offsetof(seqEnt_t, angles), MEMBER_SIZEOF(seqEnt_t, angles)},
00177     {"omega", V_VECTOR, offsetof(seqEnt_t, omega), MEMBER_SIZEOF(seqEnt_t, omega)},
00178     {"color", V_VECTOR, offsetof(seqEnt_t, color), MEMBER_SIZEOF(seqEnt_t, color)},
00179     {"parent", V_STRING, offsetof(seqEnt_t, parent), 0},
00180     {"tag", V_STRING, offsetof(seqEnt_t, tag), 0},
00181     {NULL, 0, 0, 0}
00182 };
00183 
00185 static const value_t seq2D_vals[] = {
00186     {"name", V_STRING, offsetof(seq2D_t, name), 0},
00187     {"text", V_TRANSLATION_STRING, offsetof(seq2D_t, text), 0},
00188     {"font", V_STRING, offsetof(seq2D_t, font), 0},
00189     {"image", V_STRING, offsetof(seq2D_t, image), 0},
00190     {"pos", V_POS, offsetof(seq2D_t, pos), MEMBER_SIZEOF(seq2D_t, pos)},
00191     {"speed", V_POS, offsetof(seq2D_t, speed), MEMBER_SIZEOF(seq2D_t, speed)},
00192     {"size", V_POS, offsetof(seq2D_t, size), MEMBER_SIZEOF(seq2D_t, size)},
00193     {"enlarge", V_POS, offsetof(seq2D_t, enlarge), MEMBER_SIZEOF(seq2D_t, enlarge)},
00194     {"bgcolor", V_COLOR, offsetof(seq2D_t, bgcolor), MEMBER_SIZEOF(seq2D_t, bgcolor)},
00195     {"color", V_COLOR, offsetof(seq2D_t, color), MEMBER_SIZEOF(seq2D_t, color)},
00196     {"fade", V_COLOR, offsetof(seq2D_t, fade), MEMBER_SIZEOF(seq2D_t, fade)},
00197     {"align", V_ALIGN, offsetof(seq2D_t, align), MEMBER_SIZEOF(seq2D_t, align)},
00198     {"relative", V_BOOL, offsetof(seq2D_t, relativePos), MEMBER_SIZEOF(seq2D_t, relativePos)},
00199     {NULL, 0, 0, 0},
00200 };
00201 
00206 static void SEQ_SetCamera (sequenceContext_t *context)
00207 {
00208     if (!viddef.viewWidth || !viddef.viewHeight)
00209         return;
00210 
00211     /* advance time */
00212     VectorMA(context->camera.origin, cls.frametime, context->camera.speed, context->camera.origin);
00213     VectorMA(context->camera.angles, cls.frametime, context->camera.omega, context->camera.angles);
00214     context->camera.zoom += cls.frametime * context->camera.dzoom;
00215     context->camera.dist += cls.frametime * context->camera.ddist;
00216 
00217     /* set camera */
00218     VectorCopy(context->camera.origin, cl.cam.origin);
00219     VectorCopy(context->camera.angles, cl.cam.angles);
00220 
00221     AngleVectors(cl.cam.angles, cl.cam.axis[0], cl.cam.axis[1], cl.cam.axis[2]);
00222     VectorMA(cl.cam.origin, -context->camera.dist, cl.cam.axis[0], cl.cam.camorg);
00223     cl.cam.zoom = max(context->camera.zoom, MIN_ZOOM);
00224     /* fudge to get isometric and perspective modes looking similar */
00225     if (cl_isometric->integer)
00226         cl.cam.zoom /= 1.35;
00227     CL_ViewCalcFieldOfViewX();
00228 }
00229 
00230 
00235 static seqEnt_t *SEQ_FindEnt (sequenceContext_t *context, const char *name)
00236 {
00237     seqEnt_t *se;
00238     int i;
00239 
00240     for (i = 0, se = context->ents; i < context->numEnts; i++, se++)
00241         if (se->inuse && !strncmp(se->name, name, MAX_VAR))
00242             break;
00243     if (i < context->numEnts)
00244         return se;
00245     else
00246         return NULL;
00247 }
00248 
00249 
00254 static seq2D_t *SEQ_Find2D (sequenceContext_t *context, const char *name)
00255 {
00256     seq2D_t *s2d;
00257     int i;
00258 
00259     for (i = 0, s2d = context->obj2Ds; i < context->numObj2Ds; i++, s2d++)
00260         if (s2d->inuse && !strcmp(s2d->name, name))
00261             break;
00262     if (i < context->numObj2Ds)
00263         return s2d;
00264     else
00265         return NULL;
00266 }
00267 
00275 static void SEQ_Render3D (sequenceContext_t *context)
00276 {
00277     entity_t ent;
00278     seqEnt_t *se;
00279     int i;
00280 
00281     /* set camera */
00282     SEQ_SetCamera(context);
00283 
00284     /* render sequence */
00285     for (i = 0, se = context->ents; i < context->numEnts; i++, se++)
00286         if (se->inuse) {
00287             /* advance in time */
00288             VectorMA(se->origin, cls.frametime, se->speed, se->origin);
00289             VectorMA(se->angles, cls.frametime, se->omega, se->angles);
00290             R_AnimRun(&se->as, se->model, context->animspeed->integer * cls.frametime);
00291 
00292             /* add to scene */
00293             memset(&ent, 0, sizeof(ent));
00294             ent.model = se->model;
00295             ent.skinnum = se->skin;
00296             ent.as = se->as;
00297             ent.alpha = se->alpha;
00298 
00299             R_EntitySetOrigin(&ent, se->origin);
00300             VectorCopy(se->origin, ent.oldorigin);
00301             VectorCopy(se->angles, ent.angles);
00302 
00303             if (se->parent && se->tag) {
00304                 seqEnt_t *parent;
00305 
00306                 parent = SEQ_FindEnt(context, se->parent);
00307                 if (parent)
00308                     ent.tagent = parent->ep;
00309                 ent.tagname = se->tag;
00310             }
00311 
00312             /* add to render list */
00313             se->ep = R_GetFreeEntity();
00314             R_AddEntity(&ent);
00315         }
00316 }
00317 
00318 
00323 static void SEQ_Render2D (sequenceContext_t *context)
00324 {
00325     seq2D_t *s2d;
00326     int i, j;
00327     int height = 0;
00328     vec3_t pos;
00329 
00330     /* center screen */
00331     pos[0] = (viddef.virtualWidth - VID_NORM_WIDTH) / 2;
00332     pos[1] = (viddef.virtualHeight - VID_NORM_HEIGHT) / 2;
00333     pos[2] = 0;
00334     UI_Transform(pos, NULL, NULL);
00335 
00336     /* add texts */
00337     for (i = 0, s2d = context->obj2Ds; i < context->numObj2Ds; i++, s2d++)
00338         if (s2d->inuse) {
00339             if (s2d->relativePos && height > 0) {
00340                 s2d->pos[1] += height;
00341                 s2d->relativePos = qfalse;
00342             }
00343             /* advance in time */
00344             for (j = 0; j < 4; j++) {
00345                 s2d->color[j] += cls.frametime * s2d->fade[j];
00346                 if (s2d->color[j] < 0.0)
00347                     s2d->color[j] = 0.0;
00348                 else if (s2d->color[j] > 1.0)
00349                     s2d->color[j] = 1.0;
00350             }
00351             for (j = 0; j < 2; j++) {
00352                 s2d->pos[j] += cls.frametime * s2d->speed[j];
00353                 s2d->size[j] += cls.frametime * s2d->enlarge[j];
00354             }
00355 
00356             /* outside the screen? */
00358             /*if (s2d->pos[1] >= VID_NORM_HEIGHT || s2d->pos[0] >= VID_NORM_WIDTH)
00359                 continue;*/
00360 
00361             /* render */
00362             R_Color(s2d->color);
00363 
00364             /* image can be background */
00365             if (s2d->image[0] != '\0') {
00366                 const image_t *image = R_FindImage(s2d->image, it_pic);
00367                 R_DrawImage(s2d->pos[0], s2d->pos[1], image);
00368             }
00369 
00370             /* bgcolor can be overlay */
00371             if (s2d->bgcolor[3] > 0.0)
00372                 R_DrawFill(s2d->pos[0], s2d->pos[1], s2d->size[0], s2d->size[1], s2d->bgcolor);
00373 
00374             /* render */
00375             R_Color(s2d->color);
00376 
00377             /* gettext placeholder */
00378             if (s2d->text) {
00379                 int maxWidth = (int) s2d->size[0];
00380                 if (maxWidth <= 0)
00381                     maxWidth = VID_NORM_WIDTH;
00382                 height += UI_DrawString(s2d->font, s2d->align, s2d->pos[0], s2d->pos[1], s2d->pos[0], maxWidth, -1 , _(s2d->text), 0, 0, NULL, qfalse, LONGLINES_WRAP);
00383             }
00384         }
00385     R_Color(NULL);
00386 
00387     UI_Transform(NULL, NULL, NULL);
00388 }
00389 
00395 static void SEQ_ClickEvent (sequenceContext_t *context)
00396 {
00397     context->endClickLoop = qtrue;
00398 }
00399 
00400 static qboolean SEQ_InitSequence (sequenceContext_t *context, const char *name)
00401 {
00402     sequence_t *sp;
00403     int i;
00404 
00405     /* find sequence */
00406     for (i = 0, sp = sequences; i < numSequences; i++, sp++)
00407         if (!strcmp(name, sp->name))
00408             break;
00409     if (i >= numSequences) {
00410         Com_Printf("Couldn't find sequence '%s'\n", name);
00411         return qfalse;
00412     }
00413 
00414     memset(context, 0, sizeof(*context));
00415     context->numEnts = 0;
00416     context->numObj2Ds = 0;
00417     context->time = cl.time;
00418     context->currentCmd = sp->start;
00419     context->endCmd = sp->start + sp->length;
00420     context->animspeed = Cvar_Get("seq_animspeed", "1000", 0, NULL);
00421 
00422     return qtrue;
00423 }
00424 
00425 static void SEQ_StopSequence (sequenceContext_t *context)
00426 {
00427     context->endClickLoop = qtrue;
00428 }
00429 
00435 static qboolean SEQ_Execute (sequenceContext_t *context)
00436 {
00437     seqCmd_t *sc;
00438 
00439     /* we are inside a waiting command */
00440     if (context->time > cl.time) {
00441         /* if we clicked a button we end the waiting loop */
00442         if (context->endClickLoop) {
00443             context->time = cl.time;
00444             context->endClickLoop = qfalse;
00445         }
00446     }
00447 
00448     /* run script */
00449     while (context->time <= cl.time) {
00450         /* test for finish */
00451         if (context->currentCmd >= context->endCmd) {
00452             SEQ_StopSequence(context);
00453             return qfalse;
00454         }
00455 
00456         /* call handler */
00457         sc = &seqCmds[context->currentCmd];
00458         context->currentCmd += sc->handler(context, sc->name, sc->data);
00459     }
00460 
00461     return qtrue;
00462 }
00463 
00464 /* =========================================================== */
00465 
00471 static int SEQ_ExecuteClick (sequenceContext_t *context, const char *name, const char *data)
00472 {
00473     /* if a CL_SequenceClick_f event was called */
00474     if (context->endClickLoop) {
00475         context->endClickLoop = qfalse;
00476         /* increase the command counter by 1 */
00477         return 1;
00478     }
00479     context->time += 1000;
00480     /* don't increase the command counter - stay at click command */
00481     return 0;
00482 }
00483 
00488 static int SEQ_ExecuteWait (sequenceContext_t *context, const char *name, const char *data)
00489 {
00490     context->time += 1000 * atof(name);
00491     return 1;
00492 }
00493 
00500 static int SEQ_ExecutePrecache (sequenceContext_t *context, const char *name, const char *data)
00501 {
00502     if (!strcmp(name, "models")) {
00503         while (*data) {
00504             Com_DPrintf(DEBUG_CLIENT, "Precaching model: %s\n", data);
00505             R_RegisterModelShort(data);
00506             data += strlen(data) + 1;
00507         }
00508     } else if (!strcmp(name, "pics")) {
00509         while (*data) {
00510             Com_DPrintf(DEBUG_CLIENT, "Precaching image: %s\n", data);
00511             R_RegisterImage(data);
00512             data += strlen(data) + 1;
00513         }
00514     } else
00515         Com_Printf("SEQ_Precache: unknown format '%s'\n", name);
00516     return 1;
00517 }
00518 
00522 static int SEQ_ExecuteCamera (sequenceContext_t *context, const char *name, const char *data)
00523 {
00524     /* get values */
00525     while (*data) {
00526         const value_t *vp;
00527         for (vp = seqCamera_vals; vp->string; vp++)
00528             if (!strcmp(data, vp->string)) {
00529                 data += strlen(data) + 1;
00530                 Com_EParseValue(&context->camera, data, vp->type, vp->ofs, vp->size);
00531                 break;
00532             }
00533         if (!vp->string)
00534             Com_Printf("SEQ_Camera: unknown token '%s'\n", data);
00535 
00536         data += strlen(data) + 1;
00537     }
00538     return 1;
00539 }
00540 
00547 static int SEQ_ExecuteModel (sequenceContext_t *context, const char *name, const char *data)
00548 {
00549     /* get sequence entity */
00550     seqEnt_t *se = SEQ_FindEnt(context, name);
00551     if (!se) {
00552         int i;
00553         /* create new sequence entity */
00554         for (i = 0, se = context->ents; i < context->numEnts; i++, se++)
00555             if (!se->inuse)
00556                 break;
00557         if (i >= context->numEnts) {
00558             if (context->numEnts >= MAX_SEQENTS)
00559                 Com_Error(ERR_FATAL, "Too many sequence entities");
00560             se = &context->ents[context->numEnts++];
00561         }
00562         /* allocate */
00563         memset(se, 0, sizeof(*se));
00564         se->inuse = qtrue;
00565         Q_strncpyz(se->name, name, sizeof(se->name));
00566         VectorSet(se->color, 0.7, 0.7, 0.7);
00567     }
00568 
00569     /* get values */
00570     while (*data) {
00571         const value_t *vp;
00572         for (vp = seqEnt_vals; vp->string; vp++)
00573             if (!strcmp(data, vp->string)) {
00574                 data += strlen(data) + 1;
00575                 Com_EParseValue(se, data, vp->type, vp->ofs, vp->size);
00576                 break;
00577             }
00578         if (!vp->string) {
00579             if (!strcmp(data, "model")) {
00580                 data += strlen(data) + 1;
00581                 Com_DPrintf(DEBUG_CLIENT, "Registering model: %s\n", data);
00582                 se->model = R_RegisterModelShort(data);
00583             } else if (!strcmp(data, "anim")) {
00584                 data += strlen(data) + 1;
00585                 Com_DPrintf(DEBUG_CLIENT, "Change anim to: %s\n", data);
00586                 R_AnimChange(&se->as, se->model, data);
00587             } else
00588                 Com_Printf("SEQ_Model: unknown token '%s'\n", data);
00589         }
00590 
00591         data += strlen(data) + 1;
00592     }
00593     return 1;
00594 }
00595 
00600 static int SEQ_ExecuteMusic (sequenceContext_t *context, const char *name, const char *data)
00601 {
00602     Com_Printf("change music to %s\n", name);
00603     Cvar_Set("snd_music", name);
00604     return 1;
00605 }
00606 
00611 static int SEQ_ExecuteSound (sequenceContext_t *context, const char *name, const char *data)
00612 {
00613     S_StartLocalSample(name, SND_VOLUME_DEFAULT);
00614     return 1;
00615 }
00616 
00623 static int SEQ_Execute2Dobj (sequenceContext_t *context, const char *name, const char *data)
00624 {
00625     seq2D_t *s2d;
00626     const value_t *vp;
00627     int i;
00628 
00629     /* get sequence text */
00630     s2d = SEQ_Find2D(context, name);
00631     if (!s2d) {
00632         /* create new sequence text */
00633         for (i = 0, s2d = context->obj2Ds; i < context->numObj2Ds; i++, s2d++)
00634             if (!s2d->inuse)
00635                 break;
00636         if (i >= context->numObj2Ds) {
00637             if (context->numObj2Ds >= MAX_SEQ2DS)
00638                 Com_Error(ERR_FATAL, "Too many sequence 2d objects");
00639             s2d = &context->obj2Ds[context->numObj2Ds++];
00640         }
00641         /* allocate */
00642         memset(s2d, 0, sizeof(*s2d));
00643         for (i = 0; i < 4; i++)
00644             s2d->color[i] = 1.0f;
00645         s2d->inuse = qtrue;
00646         Q_strncpyz(s2d->font, "f_big", sizeof(s2d->font));  /* default font */
00647         Q_strncpyz(s2d->name, name, sizeof(s2d->name));
00648     }
00649 
00650     /* get values */
00651     while (*data) {
00652         for (vp = seq2D_vals; vp->string; vp++)
00653             if (!strcmp(data, vp->string)) {
00654                 data += strlen(data) + 1;
00655                 switch (vp->type) {
00656                 case V_TRANSLATION_STRING:
00657                     data++;
00658                 case V_CLIENT_HUNK_STRING:
00659                     Mem_PoolStrDupTo(data, (char**) ((char*)s2d + (int)vp->ofs), cl_genericPool, 0);
00660                     break;
00661 
00662                 default:
00663                     Com_EParseValue(s2d, data, vp->type, vp->ofs, vp->size);
00664                     break;
00665                 }
00666                 break;
00667             }
00668         if (!vp->string)
00669             Com_Printf("SEQ_Text: unknown token '%s'\n", data);
00670 
00671         data += strlen(data) + 1;
00672     }
00673     return 1;
00674 }
00675 
00682 static int SEQ_ExecuteRemove (sequenceContext_t *context, const char *name, const char *data)
00683 {
00684     seqEnt_t *se;
00685     seq2D_t *s2d;
00686 
00687     se = SEQ_FindEnt(context, name);
00688     if (se)
00689         se->inuse = qfalse;
00690 
00691     s2d = SEQ_Find2D(context, name);
00692     if (s2d) {
00693         s2d->inuse = qfalse;
00694 
00695         if (s2d->text) {
00696             Mem_Free(s2d->text);
00697             s2d->text = NULL;
00698         }
00699     }
00700 
00701     if (!se && !s2d)
00702         Com_Printf("SEQ_Remove: couldn't find '%s'\n", name);
00703     return 1;
00704 }
00705 
00711 static int SEQ_ExecuteCommand (sequenceContext_t *context, const char *name, const char *data)
00712 {
00713     /* add the command */
00714     Cbuf_AddText(name);
00715     return 1;
00716 }
00717 
00718 /* =========================================================== */
00719 
00723 sequenceContext_t seq;
00724 
00730 static void CL_SequenceClick_f (void)
00731 {
00732     SEQ_ClickEvent(&seq);
00733 }
00734 
00739 static void CL_SequenceStart_f (void)
00740 {
00741     const char *name, *menuName;
00742     const uiNode_t* menu;
00743 
00744     if (Cmd_Argc() < 2) {
00745         Com_Printf("Usage: %s <name> [<menu>]\n", Cmd_Argv(0));
00746         return;
00747     }
00748     name = Cmd_Argv(1);
00749 
00750     if (!SEQ_InitSequence(&seq, name))
00751         return;
00752 
00753     /* display the sequence menu */
00754     /* the default is in menu_main.ufo - menu sequence */
00755     menuName = Cmd_Argc() < 3 ? mn_sequence->string : Cmd_Argv(2);
00756     menu = UI_PushWindow(menuName, NULL);
00757     if (!menu) {
00758         Com_Printf("CL_SequenceStart_f: can't display menu '%s'\n", menuName);
00759         return;
00760     }
00761 
00762     /* If running a local server, kill it */
00763     SV_Shutdown("Server quit", qfalse);
00764     /* if still connected - disconnect */
00765     CL_Disconnect();
00766 
00767     /* init sequence state */
00768     CL_SetClientState(ca_sequence);
00769 }
00770 
00775 static void CL_SequenceEnd_f (void)
00776 {
00777     if (cls.state == ca_sequence)
00778         CL_SetClientState(ca_disconnected);
00779 }
00780 
00781 void CL_SequenceRender (void)
00782 {
00783     refdef.brushCount = 0;
00784     refdef.aliasCount = 0;
00785 
00786     if (!viddef.viewWidth || !viddef.viewHeight)
00787         return;
00788 
00789     /* still loading */
00790     if (!refdef.ready)
00791         return;
00792 
00793     if (!SEQ_Execute(&seq)) {
00794         CL_SequenceEnd_f();
00795         UI_PopWindow(qfalse);
00796         return;
00797     }
00798 
00799     refdef.numEntities = 0;
00800     refdef.mapTiles = cl.mapTiles;
00801 
00802     SEQ_Render3D(&seq);
00803 
00804     refdef.rendererFlags |= RDF_NOWORLDMODEL;
00805 
00806     /* update ref def */
00807     CL_ViewUpdateRenderData();
00808 
00809     /* render the world */
00810     R_RenderFrame();
00811 
00812     SEQ_Render2D(&seq);
00813 }
00814 
00815 void SEQ_InitStartup (void)
00816 {
00817     Cmd_AddCommand("seq_click", CL_SequenceClick_f, NULL);
00818     Cmd_AddCommand("seq_start", CL_SequenceStart_f, NULL);
00819     Cmd_AddCommand("seq_end", CL_SequenceEnd_f, NULL);
00820 }
00821 
00822 
00823 /* =========================================================== */
00824 
00825 static const char *seqCmdName[] = {
00826     "end",
00827     "wait",
00828     "click",
00829     "precache",
00830     "camera",
00831     "model",
00832     "2dobj",
00833     "music",
00834     "sound",
00835     "rem",
00836     "cmd"
00837 };
00838 
00839 #define SEQ_NUMCMDS lengthof(seqCmdName)
00840 
00844 static sequenceHandler_t seqCmdFunc[] = {
00845     NULL,
00846     SEQ_ExecuteWait,
00847     SEQ_ExecuteClick,
00848     SEQ_ExecutePrecache,
00849     SEQ_ExecuteCamera,
00850     SEQ_ExecuteModel,
00851     SEQ_Execute2Dobj,
00852     SEQ_ExecuteMusic,
00853     SEQ_ExecuteSound,
00854     SEQ_ExecuteRemove,
00855     SEQ_ExecuteCommand
00856 };
00857 CASSERT(lengthof(seqCmdFunc) == lengthof(seqCmdName));
00858 
00863 void CL_ParseSequence (const char *name, const char **text)
00864 {
00865     const char *errhead = "CL_ParseSequence: unexpected end of file (sequence ";
00866     sequence_t *sp;
00867     const char *token;
00868     int i;
00869 
00870     /* search for sequences with same name */
00871     for (i = 0; i < numSequences; i++)
00872         if (!strcmp(name, sequences[i].name))
00873             break;
00874 
00875     if (i < numSequences) {
00876         Com_Printf("CL_ParseSequence: sequence def \"%s\" with same name found, second ignored\n", name);
00877         return;
00878     }
00879 
00880     /* initialize the sequence */
00881     if (numSequences >= MAX_SEQUENCES)
00882         Com_Error(ERR_FATAL, "Too many sequences");
00883 
00884     sp = &sequences[numSequences++];
00885     memset(sp, 0, sizeof(*sp));
00886     Q_strncpyz(sp->name, name, sizeof(sp->name));
00887     sp->start = numSeqCmds;
00888 
00889     /* get it's body */
00890     token = Com_Parse(text);
00891 
00892     if (!*text || *token != '{') {
00893         Com_Printf("CL_ParseSequence: sequence def \"%s\" without body ignored\n", name);
00894         numSequences--;
00895         return;
00896     }
00897 
00898     do {
00899         token = Com_EParse(text, errhead, name);
00900         if (!*text)
00901             break;
00902     next_cmd:
00903         if (*token == '}')
00904             break;
00905 
00906         /* check for commands */
00907         for (i = 0; i < SEQ_NUMCMDS; i++)
00908             if (!strcmp(token, seqCmdName[i])) {
00909                 int maxLength = MAX_DATA_LENGTH;
00910                 int depth;
00911                 char *data;
00912                 seqCmd_t *sc;
00913 
00914                 /* found a command */
00915                 token = Com_EParse(text, errhead, name);
00916                 if (!*text)
00917                     return;
00918 
00919                 if (numSeqCmds >= MAX_SEQCMDS)
00920                     Com_Error(ERR_FATAL, "Too many sequence commands");
00921 
00922                 /* init seqCmd */
00923                 sc = &seqCmds[numSeqCmds++];
00924                 memset(sc, 0, sizeof(*sc));
00925                 sc->handler = seqCmdFunc[i];
00926                 sp->length++;
00927 
00928                 /* copy name */
00929                 Q_strncpyz(sc->name, token, sizeof(sc->name));
00930 
00931                 /* read data */
00932                 token = Com_EParse(text, errhead, name);
00933                 if (!*text)
00934                     return;
00935                 if (*token != '{')
00936                     goto next_cmd;
00937 
00938                 depth = 1;
00939                 data = &sc->data[0];
00940                 while (depth) {
00941                     if (maxLength <= 0) {
00942                         Com_Printf("Too much data for sequence %s", sc->name);
00943                         break;
00944                     }
00945                     token = Com_EParse(text, errhead, name);
00946                     if (!*text)
00947                         return;
00948 
00949                     if (*token == '{')
00950                         depth++;
00951                     else if (*token == '}')
00952                         depth--;
00953                     if (depth) {
00954                         Q_strncpyz(data, token, maxLength);
00955                         data += strlen(token) + 1;
00956                         maxLength -= (strlen(token) + 1);
00957                     }
00958                 }
00959                 break;
00960             }
00961 
00962         if (i == SEQ_NUMCMDS) {
00963             Com_Printf("CL_ParseSequence: unknown command \"%s\" ignored (sequence %s)\n", token, name);
00964             Com_EParse(text, errhead, name);
00965         }
00966     } while (*text);
00967 }

Generated by  doxygen 1.6.2