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