1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <assert.h>
6
7 #include "xtux.h"
8 #include "server.h"
9 #include "entity.h"
10 #include "world.h"
11 #include "sv_map.h"
12 #include "clients.h"
13 #include "sv_netmsg_send.h"
14 #include "event.h"
15 #include "game.h"
16 #include "weapon.h"
17
18 extern map_t *map;
19 extern game_t game;
20 extern float sin_lookup[DEGREES];
21 extern float cos_lookup[DEGREES];
22 extern byte num_entity_types;
23 extern server_t server;
24
25 /* Each event read in from the map (section EVENT) is identified by a symbol
26 (printable character). Multiple map tiles (EVENTDATA) can have the same
27 event value. event_symbol_table keeps track of these, which are used in
28 read_event_data() to fill in the event map layer with the number of the
29 event, that is looked up in the event_tab[] array. */
30 static char event_symbol_table[256];
31 static int events = 0;
32 static event_t *event_tab; /* malloc'd to size events */
33
34 static void event_update(event_t *event);
35 static void update_virtual_entity(event_t *event);
36
37 /* Delete all current events */
event_reset(void)38 void event_reset(void)
39 {
40
41 if( events ) {
42 free(event_tab);
43 events = 0;
44 }
45 memset(event_symbol_table, 0, 256);
46
47 }
48
49
50 static char *event_name[NUM_EVENTS] = {
51 "NONE",
52 "MESSAGE",
53 "TELEPORT",
54 "ENDLEVEL",
55 "DAMAGE",
56 "MAP_TARGET",
57 "TRIGGER",
58 "SET_OBJECTIVE",
59 "OBJECTIVE_COMPLETE",
60 "DOOR",
61 "LOSEWEAPONS",
62 "LOOKAT"
63 };
64
65 #define CAN_PASS 0
66 #define NO_PASS 1
67 #define DONT_MOVE 2
68
event_trigger_none(entity * ent,event_t * event)69 static int event_trigger_none(entity *ent, event_t *event)
70 {
71
72 return 0;
73
74 }
75
event_trigger_message(entity * ent,event_t * event)76 static int event_trigger_message(entity *ent, event_t *event)
77 {
78
79 if( ent->cl && event->data.message.text[0] ) {
80 sv_netmsg_send_gamemessage(ent->cl, event->data.message.text, 0);
81 }
82
83 return 0;
84 }
85
event_trigger_teleport(entity * ent,event_t * event)86 static int event_trigger_teleport(entity *ent, event_t *event)
87 {
88
89 ent->x = event->data.teleport.x * TILE_W;
90 ent->y = event->data.teleport.y * TILE_H;
91 ent->dir = event->data.teleport.dir;
92 ent->x_v = sin_lookup[ent->dir] * event->data.teleport.speed;
93 ent->y_v = -cos_lookup[ent->dir] * event->data.teleport.speed;
94 entity_spawn_effect(ent);
95 return DONT_MOVE; /* We will handle new position, not calling functions */
96
97 }
98
event_trigger_damage(entity * ent,event_t * event)99 static int event_trigger_damage(entity *ent, event_t *event)
100 {
101
102 ent->health -= event->data.damage.damage;
103 return 0;
104
105 }
106
event_trigger_endlevel(entity * ent,event_t * event)107 static int event_trigger_endlevel(entity *ent, event_t *event)
108 {
109
110 strncpy(game.next_map_name, event->data.endlevel.map, NETMSG_STRLEN);
111 game.changelevel = 1;
112 return 0;
113 }
114
event_trigger_map_target(entity * ent,event_t * event)115 static int event_trigger_map_target(entity *ent, event_t *event)
116 {
117
118 if( ent->cl ) {
119 sv_netmsg_send_map_target(ent->cl, event->data.map_target.active,
120 event->data.map_target.target);
121 if( event->data.map_target.text[0] )
122 sv_netmsg_send_gamemessage(ent->cl, event->data.map_target.text,0);
123 }
124
125 return 0;
126
127 }
128
event_trigger_trigger(entity * ent,event_t * event)129 static int event_trigger_trigger(entity *ent, event_t *event)
130 {
131 int change;
132 event_t *targ;
133
134 event->data.trigger.on = !event->data.trigger.on;
135 if( event->data.trigger.target ) {
136 targ = &event_tab[event->data.trigger.target];
137 change = (event->data.trigger.on? 1:-1) * event->data.trigger.val;
138 targ->value += change;
139 event_update(targ);
140 }
141
142 if( event->data.trigger.on && event->data.trigger.text[0] )
143 sv_netmsg_send_gamemessage(0, event->data.trigger.text, 1);
144
145 return 0;
146
147 }
148
event_trigger_set_objective(entity * ent,event_t * event)149 static int event_trigger_set_objective(entity *ent, event_t *event)
150 {
151
152 sv_netmsg_send_objective(0, event->data.set_objective.text, 1);
153 return 0;
154
155 }
156
event_trigger_objective_complete(entity * ent,event_t * event)157 static int event_trigger_objective_complete(entity *ent, event_t *event)
158 {
159
160 game.objective_complete = 1;
161 sv_netmsg_send_gamemessage(0, event->data.objective_complete.text, 1);
162 return 0;
163
164 }
165
166
event_trigger_door(entity * ent,event_t * event)167 static int event_trigger_door(entity *ent, event_t *event)
168 {
169
170 if( event->active ) {
171 /* Check to see if virtual entity is still animating through change */
172 if( event->virtual && event->virtual->mode != ALIVE )
173 return NO_PASS;
174 else
175 return CAN_PASS;
176 } else
177 return NO_PASS;
178
179 }
180
181
event_trigger_loseweapons(entity * ent,event_t * event)182 static int event_trigger_loseweapons(entity *ent, event_t *event)
183 {
184
185 weapon_reset(ent);
186 memset(ent->ammo, 0, sizeof(ent->ammo));
187
188 if( ent->cl && event->data.loseweapons.text[0] ) {
189 sv_netmsg_send_gamemessage(ent->cl, event->data.loseweapons.text, 0);
190 }
191
192 return 0;
193
194 }
195
196
event_trigger_lookat(entity * ent,event_t * event)197 static int event_trigger_lookat(entity *ent, event_t *event)
198 {
199
200 if( ent->cl && event->data.map_target.text[0] ) {
201 sv_netmsg_send_gamemessage(ent->cl, event->data.lookat.text, 0);
202 }
203
204 ent->lookatdir = event->data.lookat.dir;
205 ent->speed = 0;
206
207 return 0;
208
209 }
210
211
212
213 static int (*event_trigger_handle[NUM_EVENTS])(entity *, event_t *) = {
214 event_trigger_none,
215 event_trigger_message,
216 event_trigger_teleport,
217 event_trigger_endlevel,
218 event_trigger_damage,
219 event_trigger_map_target,
220 event_trigger_trigger,
221 event_trigger_set_objective,
222 event_trigger_objective_complete,
223 event_trigger_door,
224 event_trigger_loseweapons,
225 event_trigger_lookat,
226 };
227
228
229 /* Time in msecs between triggers of an event */
230 #define TRIGGER_TIME 750
231
event_trigger(entity * ent,byte id)232 int event_trigger(entity *ent, byte id)
233 {
234 event_t *event;
235 int val;
236
237 if( id < events ) {
238 event = &event_tab[id];
239
240 /* Doors block when inactive */
241 if( event->active == 0 && event->type != EVENT_DOOR )
242 return 0;
243
244 if( event->exclusive && ent->class != GOODIE )
245 return 0;
246
247 if( event->type != EVENT_DOOR ) { /* Doors are special */
248 if( server.now - event->last_trigger >= TRIGGER_TIME )
249 event->last_trigger = server.now;
250 else
251 return 0; /* Not ready to be triggered */
252 }
253
254 val = event_trigger_handle[event->type](ent, event);
255
256 if( event->type != EVENT_DOOR )
257 event->active = event->repeat;
258
259
260 return val;
261
262 }
263
264 return 0;
265
266 }
267
268
269 typedef struct tmp_node_struct {
270 struct tmp_node_struct *next;
271 event_t event;
272 } tmp_node;
273
274 tmp_node *event_root, *event_tail;
275
event_new(void)276 static event_t *event_new(void)
277 {
278 tmp_node *ptr;
279
280 if( (ptr = (tmp_node *)malloc( sizeof(tmp_node) )) == NULL ) {
281 perror("malloc");
282 ERR_QUIT("Allocating new tmp node for an event", -1);
283 }
284
285 /* Add it to the list */
286 if( event_root == NULL )
287 event_root = ptr; /* The new event_root entity */
288
289 if( event_tail != NULL )
290 event_tail->next = ptr;
291
292 event_tail = ptr;
293 event_tail->next = NULL; /* end of list */
294 ptr->event.good = 0; /* Not good by default */
295
296 events++;
297
298 return &ptr->event;
299
300 }
301
302
303 /* Setup the event layer to point to the right events and fill in trigger events */
event_setup_finish(void)304 int event_setup_finish(void)
305 {
306 tmp_node *ptr, *next;
307 int i;
308 char ep;
309
310 if( events <= 0 )
311 return 0; /* No events */
312
313 events++; /* We want an EVENT_NONE at the start */
314
315 if( (event_tab = malloc( sizeof(event_t) * events )) == NULL )
316 ERR_QUIT("Error allocating event_tab[] array", -1);
317
318 event_tab[0].type = EVENT_NONE;
319 event_tab[0].active = 0;
320 event_tab[0].repeat = 0;
321 event_tab[0].visible = 0;
322
323 events = 1; /* So far we have 1 good event (EVENT_NONE) */
324 ptr = event_root;
325 for( i=1 ; ptr != NULL ; i++ ) {
326 next = ptr->next;
327 if( ptr->event.good ) {
328 event_tab[i] = ptr->event;
329 events++;
330 } else {
331 printf("Dropping event type %s\n", event_name[ptr->event.type]);
332 event_tab[i].type = EVENT_NONE;
333 }
334 free(ptr);
335 ptr = next;
336 }
337
338 event_root = NULL;
339 event_tail = NULL;
340
341 for(i=0 ; i<map->width * map->height ; i++ )
342 map->event[i] = event_symbol_table[ (int)map->event[i] ];
343
344 for(i = 0; i < events; i++) {
345 if( event_tab[i].type == EVENT_TRIGGER ) {
346 ep = event_symbol_table[event_tab[i].data.trigger.letter];
347 event_tab[i].data.trigger.target = ep;
348 if( ep ) {
349 if( event_tab[i].data.trigger.on ) { /* Do initial trigger */
350 event_t *targ;
351 targ = &event_tab[(int)ep];
352 targ->value += event_tab[i].data.trigger.val;
353 event_update(targ);
354 }
355 } else {
356 printf("No such event \"%c\" for trigger\n",
357 event_tab[i].data.trigger.letter);
358 }
359 }
360 }
361
362 return 1;
363
364 }
365
366
367 /* Draw the events for specified client */
event_draw(client_t * cl)368 void event_draw(client_t *cl)
369 {
370 animation_t *ani;
371 ent_type_t *type;
372 event_t *event;
373 netmsg msg;
374 int x, y;
375 int x_start, y_start;
376 int x_max, y_max;
377 int mode;
378 byte e;
379
380 if( map->event == NULL )
381 return;
382
383 x_start = cl->screenpos.x/TILE_W;
384 y_start = cl->screenpos.y/TILE_H;
385
386 x_max = MIN( (cl->screenpos.x + cl->view_w)/TILE_W + 1, map->width );
387 y_max = MIN( (cl->screenpos.y + cl->view_h)/TILE_H + 1, map->height );
388
389 for( y=y_start ; y < y_max ; y++ ) {
390 for( x=x_start ; x < x_max ; x++ ) {
391 if( (e = map->event[ y*map->width + x ]) ) {
392 if( e >= events )
393 continue;
394 event = &event_tab[e];
395 if( !event->visible )
396 continue;
397
398 /* Doors "activeness" is different */
399 if( event->active == 0 && event->type != EVENT_DOOR )
400 continue;
401
402 if( event->virtual ) {
403 update_virtual_entity(event);
404 type = event->virtual->type_info;
405 assert( type != NULL );
406
407 /* Make triggers act correctly */
408 if( event->type == EVENT_TRIGGER )
409 mode = event->data.trigger.on? ALIVE : DEAD;
410 else
411 mode = event->virtual->mode;
412 ani = type->animation[mode];
413
414 if( ani != NULL ) {
415 msg = entity_to_netmsg(event->virtual);
416 msg.type = NETMSG_ENTITY;
417 msg.entity.x = x * TILE_W;
418 msg.entity.y = y * TILE_H;
419 msg.entity.mode = mode;
420 net_put_message(cl->nc, msg);
421 }
422
423 } else { /* If no virtual entity maybe some pixel effects */
424
425 msg.type = NETMSG_PARTICLES;
426 msg.particles.effect = P_TELEPORT;
427
428 msg.particles.length = TILE_W/2;
429 msg.particles.x = x * TILE_W + TILE_W/2;
430 msg.particles.y = y * TILE_H + TILE_H/2;
431
432 if( event_tab[e].type == EVENT_TELEPORT ) {
433 msg.particles.color1 = COL_GRAY;
434 msg.particles.color2 = COL_YELLOW;
435 net_put_message(cl->nc, msg);
436 } else if( event_tab[e].type == EVENT_ENDLEVEL ) {
437 msg.particles.color1 = COL_PINK;
438 msg.particles.color2 = COL_PURPLE;
439 net_put_message(cl->nc, msg);
440 }
441 }
442 }
443 }
444 }
445
446 }
447
448
449
450
451
event_new_none(event_t * event,const char * args)452 static void event_new_none(event_t *event, const char *args)
453 {
454
455 event->good = 1;
456
457 }
458
459
event_new_message(event_t * event,const char * args)460 static void event_new_message(event_t *event, const char *args)
461 {
462
463 if( args ) {
464 strncpy(event->data.message.text, args, TEXTMESSAGE_STRLEN);
465 event->good = 1;
466 }
467
468 }
469
470
event_new_teleport(event_t * event,const char * args)471 static void event_new_teleport(event_t *event, const char *args)
472 {
473 int x, y, dir, speed;
474
475 if( sscanf(args, "%d %d %d %d", &x, &y, &dir, &speed) == 4 ) {
476 event->data.teleport.x = x;
477 event->data.teleport.y = y;
478 event->data.teleport.dir = dir;
479 event->data.teleport.speed = speed;
480 event->good = 1;
481 } else {
482 printf("Error parsing teleport event, args = \"%s\"\n", args);
483 }
484
485 }
486
487
event_new_endlevel(event_t * event,const char * args)488 static void event_new_endlevel(event_t *event, const char *args)
489 {
490 if( args ) {
491 strncpy(event->data.endlevel.map, args, NETMSG_STRLEN);
492 event->good = 1;
493 }
494 }
495
event_new_damage(event_t * event,const char * args)496 static void event_new_damage(event_t *event, const char *args)
497 {
498 int damage;
499
500 if( sscanf(args, "%d", &damage) == 1 ) {
501 event->data.damage.damage = damage;
502 event->good = 1;
503 } else {
504 printf("Error parsing damage object\n");
505 }
506
507 }
508
509
event_new_map_target(event_t * event,const char * args)510 static void event_new_map_target(event_t *event, const char *args)
511 {
512 int i, len;
513
514 if( sscanf(args, "%d %d %d",
515 (int *)&event->data.map_target.active,
516 (int *)&event->data.map_target.target.x,
517 (int *)&event->data.map_target.target.y) != 3 ) {
518 printf("Error parsing map target event\n");
519 return;
520 }
521
522 len = strlen(args);
523 for( i = 0 ; isdigit(args[i]) || isspace(args[i]) ; i++ )
524 if( i >= len )
525 return;
526
527 strncpy(event->data.map_target.text, args + i, TEXTMESSAGE_STRLEN);
528 event->good = 1;
529
530 }
531
532
event_new_trigger(event_t * event,const char * args)533 static void event_new_trigger(event_t *event, const char *args)
534 {
535 char letter, on;
536 int i, len, val;
537
538 if( sscanf(args, "%c %c %d", &letter, &on, &val) != 3 ) {
539 printf("No letter, ON/OFF flag or val in trigger \"%s\"\n",args);
540 return;
541 }
542
543 event->data.trigger.letter = letter;
544 event->data.trigger.on = (on == 'y');
545 event->data.trigger.val = val;
546
547 len = strlen(args);
548 for( i = 5 ; isspace(args[i]) || isdigit(args[i]) ; i++ )
549 if( i >= len )
550 return;
551
552 strncpy(event->data.trigger.text, args + i, TEXTMESSAGE_STRLEN);
553 event->good = 1;
554
555 }
556
event_new_set_objective(event_t * event,const char * args)557 static void event_new_set_objective(event_t *event, const char *args)
558 {
559 strncpy(event->data.set_objective.text, args, TEXTMESSAGE_STRLEN);
560 event->good = 1;
561 }
562
563
event_new_objective_complete(event_t * event,const char * args)564 static void event_new_objective_complete(event_t *event, const char *args)
565 {
566 strncpy(event->data.objective_complete.text, args, TEXTMESSAGE_STRLEN);
567 event->good = 1;
568 }
569
570
event_new_door(event_t * event,const char * args)571 static void event_new_door(event_t *event, const char *args)
572 {
573 event->good = 1;
574 }
575
576
event_new_loseweapons(event_t * event,const char * args)577 static void event_new_loseweapons(event_t *event, const char *args)
578 {
579 if( args ) {
580 strncpy(event->data.loseweapons.text, args, TEXTMESSAGE_STRLEN);
581 event->good = 1;
582 }
583 }
584
event_new_lookat(event_t * event,const char * args)585 static void event_new_lookat(event_t *event, const char *args)
586 {
587 int i, len, dir;
588
589 if( args ) {
590
591 if( sscanf(args, "%d", &dir) != 1 ) {
592 printf("No lookat dir found.\n");
593 return;
594 }
595
596 event->data.lookat.dir = dir;
597
598 len = strlen(args);
599 for( i = 0 ; isspace(args[i]) || isdigit(args[i]) ; i++ )
600 if( i >= len )
601 return;
602
603 strncpy(event->data.lookat.text, args + i, TEXTMESSAGE_STRLEN);
604 event->good = 1;
605 }
606 }
607
608
609 static void (*event_handle[NUM_EVENTS])(event_t *event, const char *args) = {
610 event_new_none,
611 event_new_message,
612 event_new_teleport,
613 event_new_endlevel,
614 event_new_damage,
615 event_new_map_target,
616 event_new_trigger,
617 event_new_set_objective,
618 event_new_objective_complete,
619 event_new_door,
620 event_new_loseweapons,
621 event_new_lookat
622 };
623
624
625 /*
626 We are passed <ENTITY_NAME> XXXX-SOME-DATA-XXXX.
627 return the entity type that matches ENTITY_NAME (or -1 in error)
628 set len to be the position where the XXX-SOME-DATA-XXX data starts
629 */
630
event_get_virtual_entity(const char * args,int * len)631 int event_get_virtual_entity(const char *args, int *len)
632 {
633 ent_type_t *et;
634 char *p;
635 int i;
636
637 if( (p = strchr(args, '>')) == NULL ) {
638 printf("Error: '>' not found searching for virtual entity\n");
639 return -1;
640 }
641
642 *len = p + 1 - args;
643 args++; /* Step past "<" */
644
645 for( i=0 ; i < num_entity_types ; i++ ) {
646 if( (et = entity_type(i)) == NULL )
647 continue;
648 /* *len - 2 == length from args to '>' */
649 if( strncasecmp( et->name, args, *len - 2) == 0 ) {
650 /* printf("event_get_virtual_entity: MATCH(%s)\n", et->name); */
651 return i;
652 }
653 }
654
655 printf("No entity type found in \"%s\"\n", args);
656 return -1;
657
658 }
659
660
event_update(event_t * event)661 static void event_update(event_t *event)
662 {
663 animation_t *ani;
664 int valid = 0;
665
666 /* Check to see if value will unlock event (if it has correct relationship
667 with key)*/
668 if( event->key ) {
669 switch( event->vk_cmp ) {
670 case VK_EQ:
671 valid = (event->value == event->key);
672 break;
673 case VK_GT:
674 valid = (event->value > event->key);
675 break;
676 }
677
678 /* Change states.... */
679 if( event->active && !valid ) {
680 if( event->virtual ) {
681 if( event->virtual->type_info->animation[DYING] ) {
682 event->direction = 1;
683 event->virtual->frame = 0;
684 event->virtual->last_frame = server.now;
685 event->virtual->mode = DYING;
686 } else {
687 event->virtual->mode = DEAD;
688 }
689 }
690 event->active = 0;
691 }
692
693 if( !event->active && valid ) {
694 if( event->virtual ) {
695 if( (ani = event->virtual->type_info->animation[DYING]) ) {
696 event->virtual->frame = ani->frames - 1;
697 event->virtual->last_frame = server.now;
698 event->direction = -1;
699 event->virtual->mode = DYING;
700 } else {
701 event->virtual->mode = ALIVE;
702 }
703 }
704 event->active = 1;
705 }
706 }
707
708 }
709
710
711
update_virtual_entity(event_t * event)712 static void update_virtual_entity(event_t *event)
713 {
714 animation_t *ani;
715 entity *ent;
716 int frames;
717
718 ent = event->virtual;
719 if( (ani = ent->type_info->animation[ent->mode]) == NULL )
720 return; /* Nothing shown for this state...... */
721
722 if( ani->images > 1 ) {
723 if( ani->framelen )
724 frames = (server.now - ent->last_frame) / ani->framelen;
725 else
726 frames = 0;
727
728 if( frames > 0 ) {
729 ent->last_frame = server.now;
730 ent->frame += event->direction * frames;
731 if( ent->frame >= ani->frames ) {
732 if( ent->mode == DYING ) {
733 if( event->direction == 1 ) { /* 1 = ALIVE --> DEAD */
734 ent->mode = DEAD;
735 event->active = 0;
736 } else { /* -1 = DEAD --> ALIVE */
737 ent->mode = ALIVE;
738 event->active = 1;
739 }
740 }
741 event->direction = 1;
742 ent->frame = 0;
743 }
744
745 }
746 ent->img = ani->order[ent->frame];
747 }
748
749
750 }
751
752
read_event(const char * line)753 void read_event(const char *line)
754 {
755 event_t *event;
756 ent_type_t *et;
757 int i, len, ent_type, event_type, key;
758 val_key_cmp_t vk_cmp = VK_EQ;
759 const char *args;
760 char c, a, r, v, e; /* id character, active, repeat, visible, exclusive */
761
762 event_type = -1;
763 for(i=0 ; i<NUM_EVENTS; i++ ) {
764 len = strlen(event_name[i]);
765 if( !strncasecmp(line, event_name[i], len) ) {
766 args = line + len + 1; /* Args are 1 space after the event name */
767 /* Get symbol representation for event */
768 if( sscanf(args, "%c", &c) != 1 ) {
769 printf("Error reading EVENT symbol \"%s\"\n", line);
770 break;
771 }
772 args += 2; /* Move past the character */
773
774 /* Get settings ACTIVE REPEAT VISIBLE EXCLUSIVE flags */
775 if( sscanf(args, "%c %c %c %c", &a, &r, &v, &e) != 4 ) {
776 printf("Error reading 4 EVENT flags from \"%s\"\n", line);
777 break;
778 }
779 args += 8; /* Move past the characters */
780
781 /* Set Key for event */
782 if( !strncmp(args, "KEY", 3) ) {
783 args += 3;
784 if( *args == '>' )
785 vk_cmp = VK_GT; /* Greater than */
786 else if( *args == '=' )
787 vk_cmp = VK_EQ; /* Equal to */
788 else {
789 printf("ERROR reading vk_cmp in line = \"%s\"\n", line);
790 break;
791 }
792
793 args++;
794 if( sscanf(args, "%d", &key) != 1 ) {
795 printf("ERROR reading key value in line = \"%s\"\n", line);
796 break;
797 }
798
799 while( !isspace(*args++) ); /* Get to start of next data */
800
801 }
802
803
804 ent_type = -1;
805 /* There is a VIRTUAL entity in brackets, ie <ENT_TYPE> */
806 if( *args == '<' ) {
807 int len = 0;
808 ent_type = event_get_virtual_entity(args, &len);
809 args += len + 1; /* Step past <.*> and 1 space */
810 }
811
812 /* Make a new event, add it's symbol to the symbol table and
813 pass the rest of the line off to the individual routines to
814 fill in the rest of the event */
815 event = event_new();
816 event->type = i;
817 event->vk_cmp = vk_cmp;
818 event->key = key;
819 event->last_trigger = 0;
820 event->direction = 1; /* Play animation forwards */
821 event->active = (a == 'y');
822 event->repeat = (r == 'y');
823 event->visible = (v == 'y');
824 event->exclusive = (e == 'y');
825 event_symbol_table[(int)c] = events;
826 event_handle[i](event, args);
827
828 if( event->active )
829 event->value = event->key;
830 else
831 event->value = 0;
832
833 if( ent_type >= 0 && event->type != EVENT_NONE ) {
834 if( (event->virtual = entity_alloc()) != NULL ) {
835 memset( event->virtual, 0, sizeof( entity ) );
836 if( (et = entity_type(ent_type)) != NULL )
837 event->virtual->type_info = et;
838 event->virtual->type = ent_type;
839 event->virtual->mode = event->active? ALIVE : DEAD;
840 event->virtual->last_frame = server.now;
841 }
842 } else
843 event->virtual = NULL;
844 break;
845 }
846 }
847
848 }
849
850
event_close(void)851 void event_close(void)
852 {
853 int i;
854
855 if( events <= 0 )
856 return;
857
858 printf("Free'ing %d events.\n", events);
859
860 for( i = 0 ; i < events ; i++ ) {
861 if( event_tab[i].virtual )
862 free(event_tab[i].virtual);
863 }
864
865 free(event_tab);
866
867 }
868