00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
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
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
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
00282 SEQ_SetCamera(context);
00283
00284
00285 for (i = 0, se = context->ents; i < context->numEnts; i++, se++)
00286 if (se->inuse) {
00287
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
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
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
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
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
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
00358
00359
00360
00361
00362 R_Color(s2d->color);
00363
00364
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
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
00375 R_Color(s2d->color);
00376
00377
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
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
00440 if (context->time > cl.time) {
00441
00442 if (context->endClickLoop) {
00443 context->time = cl.time;
00444 context->endClickLoop = qfalse;
00445 }
00446 }
00447
00448
00449 while (context->time <= cl.time) {
00450
00451 if (context->currentCmd >= context->endCmd) {
00452 SEQ_StopSequence(context);
00453 return qfalse;
00454 }
00455
00456
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
00474 if (context->endClickLoop) {
00475 context->endClickLoop = qfalse;
00476
00477 return 1;
00478 }
00479 context->time += 1000;
00480
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
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
00550 seqEnt_t *se = SEQ_FindEnt(context, name);
00551 if (!se) {
00552 int i;
00553
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
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
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
00630 s2d = SEQ_Find2D(context, name);
00631 if (!s2d) {
00632
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
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));
00647 Q_strncpyz(s2d->name, name, sizeof(s2d->name));
00648 }
00649
00650
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
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
00754
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
00763 SV_Shutdown("Server quit", qfalse);
00764
00765 CL_Disconnect();
00766
00767
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
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
00807 CL_ViewUpdateRenderData();
00808
00809
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
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
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
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
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
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
00923 sc = &seqCmds[numSeqCmds++];
00924 memset(sc, 0, sizeof(*sc));
00925 sc->handler = seqCmdFunc[i];
00926 sp->length++;
00927
00928
00929 Q_strncpyz(sc->name, token, sizeof(sc->name));
00930
00931
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 }