1 /* $Header: /home/yav/catty/fkiss/RCS/kisseve.c,v 1.34 2000/10/17 05:00:59 yav Exp $
2  * KISS event extension
3  * written by yav <yav@bigfoot.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * CAUTION!
20  * Experiment of event extension, NOT STANDARD!
21  * These extensions are ONLY for checking technical problems.
22  * Now we are reseaching:
23  *  Which functions users need?
24  *  What is smart, eazy, simple description style?
25  * These problems are resolved, we'll define advanced KISS officially.
26  * BUT, THAT'S FUNCTIONS AND DESCRIPTION STYLE WILL BE DIFFERENT FROM THIS!
27  *
28  *;@EventHandler		; event extension identifier
29  *;@never()			; never happen, ignore
30  *;@initialize()		; startup event (before reading datas)
31  *;@				;  Caution! at this event
32  *;@				;  nop, debug, shell, unmap actions available.
33  *;@				;  Don't use other actions!
34  *;@	nop()			; No operation
35  *;@	debug("here!\n")	; print string to stderr for debug
36  *;@				;  arg1 string to print
37  *;@	shell("echo Hello `whoami`")	; shell
38  *;@				;  arg1 string passed to shell
39  *;@				;  Caution! No compatibility (OS depend),
40  *;@				;  and this function makes SECURITY HOLE.
41  *;@				;  So, by default this function is disabled.
42  *;@				;  ONLY -eventshell option is specified,
43  *;@				;  this function is enabled.
44  *;@	unmap("facered.cel")	; unmap cell
45  *;@begin()			; begin event (at window is mapped)
46  *;@	timer(1, 3000)		; setup timer
47  *;@				;  (same as randomtimer(arg1, arg2, 1))
48  *;@	randomtimer(1, 3000, 5000)	; setup timer at random
49  *;@				;  After arg2+(rand()%arg3) milliseconds,
50  *;@				;  event alarm(arg1) will be happen.
51  *;@				;  arg1 timer channel number [0, 63]
52  *;@				;  arg2 time (milli-second)
53  *;@				;       0 <= arg2 <= 32767 (0:disable timer)
54  *;@				;  arg3 range of random time (milli-second)
55  *;@				;       1 <= arg3 <= 32768-arg2
56  *;@end()			; end event ([quit] is selected)
57  *;@	sound("bye.au")		; play PCM sound
58  *;@				;  arg1 pcm filename (Sun Audio file)
59  *;@alarm(1)			; timer alarm
60  *;@				;  arg1 timer channel number [0, 63]
61  *;@press("vast.cel")		; mouse button press
62  *;@				;  arg1 cell filename or object mark
63  *;@	map("facered.cel")	; map cell
64  *;@				;  arg1 cell filename
65  *;@release("vast.cel")		; mouse button release
66  *;@				;  arg1 cell filename or object mark
67  *;@	unmap("facered.cel")	; unmap cell
68  *;@				;  arg1 cell filename
69  *;@catch(#1)			; catch object
70  *;@				;  arg1 cell filename or object mark
71  *;@	altmap("panties.cel")	; alternate map/unmap cell
72  *;@				;  arg1 cell filename
73  *;@	altmap("panties2.cel")
74  *;@drop(#1)			; release object
75  *;@				;  arg1 cell filename or object mark
76  *;@	altmap("panties.cel")
77  *;@	altmap("panties2.cel")
78  *;@fixcatch(#1)		; catch fixed object
79  *;@				;  arg1 cell filename or object mark
80  *;@	sound("iyaan.au")
81  *;@fixdrop(#1)			; release fixed object (and object return)
82  *;@				;  arg1 cell filename or object mark
83  *;@	move(#1, 10, -2)	; move object
84  *;@				;  arg1 object mark
85  *;@				;  arg2 delta x (pixel)
86  *;@				;  arg3 delta y (pixel)
87  *;@unfix(#1)			; fix value is cleared! pesi pesi done.
88  *;@				;  arg1 cell filename or object mark
89  *;@	changeset(2)		; change set
90  *;@				;  arg1 destination set number [0, setcnt-1]
91  *;@	changecol(2)		; change color group
92  *;@				;  arg1 destination color number [0, palcnt-1]
93  *;@set(1)			; set changed
94  *;@				;  arg1 set number
95  *;@col(1)			; color group changed
96  *;@				;  arg1 color number
97  *;@	quit()			; quit
98  *;@    transparent("a.cel", 8)	; change transparency rate
99  *;@				;  arg1 cell filename
100  *;@				;  arg2 transparency rate add value [-256, 256]
101  *;@    windowsize(-200, -100)	; change top level window size
102  *;@				; and viewport position is re-centered
103  *;@				;  arg1 width add value (pixel)
104  *;@				;  arg2 height add value (pixel)
105  *;@    viewport(16, 8)		; change viewport position
106  *;@				;  arg1 viewport position x add value (pixel)
107  *;@				;  arg2 viewport position y add value (pixel)
108  *
109  * number
110  *	10			decimal number
111  *	010	(= 8)		octal number heading "0"
112  *	0x10	(= 16)		hexadecimal number heading "0x"
113  * string
114  *	"Sample string"		Any string is quoted by double quotation marks.
115  *	"\t<- Tab"		\t Tab
116  *	"Newline ->\n"		\n Newline
117  *	"\\<-Backslash"		\\ Backslash
118  *	"\"<- Doublequote"	\" Double quotation mark
119  *      "\$ <- dollar"		\$ Dollar mark
120  *				Don't use other \ escaped character!
121  * object mark
122  *	#10			Object mark is "#" started number.
123  *
124  */
125 
126 char id_kisseve[] = "$Id: kisseve.c,v 1.34 2000/10/17 05:00:59 yav Exp $";
127 
128 #include <X11/Xos.h>
129 #include <X11/Xlib.h>
130 #include <stdio.h>
131 #include "config.h"
132 #include "headers.h"
133 #include "fkiss.h"
134 #include "work.h"
135 #include "timer.h"
136 #define PUBLIC_KISSEVE_C
137 #include "extern.h"
138 
139 
140 /* #define WARN_ACTION	  64	-- warn if more actions for one event */
141 /* #define WARN_EVENT	  64	-- warn if more event number, now in extern.h */
142 /* #define WARN_SOUNDFILE 64	-- warn if more soundfiles, now in extern.h */
143 /* #define WARN_TIMER	  64	-- warn if more timer channels, now in extern.h */
144 /* #define MAXACTION	 256	-- maximum action for one event (-> extern.h)*/
145 /* #define MAXEVENT	 256	-- maximum event, now in extern.h */
146 /* #define MAXSOUNDFILE	 256	-- maximum sound file, now in extern.h */
147 /* #define MAXTIMER	 256	-- maximum timer channel, now in extern.h */
148 
149 
150 /* argument type */
151 #define OT_CEL	1		/* Cell */
152 #define OT_OBJ	2		/* Object */
153 #define OT_SND	3		/* Sound */
154 #define OT_NUM	4		/* Number */
155 #define OT_STR	5		/* String */
156 #define OT_TCH	6		/* Timer channel number */
157 #define OT_SET	7		/* Set number */
158 #define OT_COL	8		/* Color group number */
159 
160 #define EOBJN 3			/* maximum number of event arguments */
161 #define AOBJN 3			/* maximum number of action arguments */
162 #if (EOBJN > AOBJN)
163 # define MAXARGN EOBJN
164 #else
165 # define MAXARGN AOBJN
166 #endif
167 
168 typedef struct {
169   short type;			/* argument type */
170   short no;			/* argument code */
171   char *name;			/* filename */
172 } EVOBJ;			/* argument structure */
173 
174 typedef struct {
175   short n;			/* action type */
176   EVOBJ aobj[AOBJN];		/* argument */
177 } ACTION;
178 
179 
180 typedef struct {
181   short elineno;		/* cnf line number */
182   short evtype;			/* event type */
183   EVOBJ eobj[EOBJN];		/* event argument */
184   short alineno;		/* cnf line number action */
185   short actn;			/* number of actions (<= MAXACTION) */
186 				/* nothing changed with alineno, but it is:*/
187 				/* cnf line number of LAST action of event */
188 				/* (maybe this is not like it should be ?) */
189   ACTION *act;			/* actions */
190 } EVT;
191 
192 typedef struct {
193   int channel;
194   struct TMV alarmtime;
195   struct TMV starttime;
196 } TIMER;
197 
198 
199 static Bool event_ok = False;
200 static EVT *evtbl = NULL;	/* event table */
201 static int soundn = 0;		/* number of sound files (<= MAXSOUNDFILE) */
202 static char **soundlist = NULL;
203 static TIMER *timertbl = NULL;
204 static int timertbln = 0;
205 static int active_timer;	/* number of active timer-channels */
206 
207 typedef struct {
208   struct TMV tm0;		/* event occured time */
209   long event_delay;		/* event delay milliseconds */
210   int redraw_xtop, redraw_ytop;
211   int redraw_xend, redraw_yend;
212 } EVW;
213 
214 /* global buffer for error messages, such as "file not found" */
215 static char G_ERRbuf[80] = { '\0', /* fill up the rest */ };
216 
217 /* keyword table */
218 typedef struct {
219   char *str;			/* keyword */
220   short n;			/* code */
221   char argt[MAXARGN+1];		/* argument type (+1 for terminater 0) */
222 } KEYWORD_TABLE;
223 
224 #define KTBL(code,name,pt0,pt1,pt2,pt3) \
225 {name, code, {pt0, pt1, pt2, pt3}}
226 
227 static KEYWORD_TABLE event_syntax[] = {
228   /* code		keyword 	pt0	pt1	pt2	pt3 */
229   KTBL(EVE_NEVER,	"never",	0,	0,	0,	0),
230   KTBL(EVE_INITIALIZE,	"initialize",	0,	0,	0,	0),
231   KTBL(EVE_ALARM,	"alarm",	OT_TCH,	0,	0,	0),
232   KTBL(EVE_BEGIN,	"begin",	0,	0,	0,	0),
233   KTBL(EVE_END,		"end",		0,	0,	0,	0),
234   KTBL(EVE_PRESS,	"press",	OT_CEL,	0,	0,	0),
235   KTBL(EVE_RELEASE,	"release",	OT_CEL,	0,	0,	0),
236   KTBL(EVE_CATCH,	"catch",	OT_CEL,	0,	0,	0),
237   KTBL(EVE_DROP,	"drop",		OT_CEL,	0,	0,	0),
238   KTBL(EVE_FIXCATCH,	"fixcatch",	OT_CEL,	0,	0,	0),
239   KTBL(EVE_FIXDROP,	"fixdrop",	OT_CEL,	0,	0,	0),
240   KTBL(EVE_UNFIX,	"unfix",	OT_CEL,	0,	0,	0),
241   KTBL(EVE_SET,		"set",		OT_SET,	0,	0,	0),
242   KTBL(EVE_COL,		"col",		OT_COL,	0,	0,	0),
243   KTBL(EVE_IN,		"in",		OT_OBJ,	OT_OBJ,	0,	0),
244   KTBL(EVE_OUT,		"out",		OT_OBJ,	OT_OBJ,	0,	0),
245   KTBL(EVE_STILLIN,	"stillin",	OT_OBJ,	OT_OBJ,	0,	0),
246   KTBL(EVE_STILLOUT,	"stillout",	OT_OBJ,	OT_OBJ,	0,	0),
247   KTBL(EVE_COLLIDE,	"collide",	OT_CEL,	OT_CEL,	0,	0),
248   KTBL(EVE_APART,	"apart",	OT_CEL,	OT_CEL,	0,	0),
249   KTBL(EVE_VERSION,	"version",	OT_NUM,	0,	0,	0),
250   KTBL(ACT_NOP,		"nop",		0,	0,	0,	0),
251   KTBL(ACT_DEBUG,	"debug",	OT_STR,	0,	0,	0),
252   KTBL(ACT_SHELL,	"shell",	OT_STR,	0,	0,	0),
253   KTBL(ACT_UNMAP,	"unmap",	OT_CEL,	0,	0,	0),
254   KTBL(ACT_MAP,		"map",		OT_CEL,	0,	0,	0),
255   KTBL(ACT_ALTMAP,	"altmap",	OT_CEL,	0,	0,	0),
256   KTBL(ACT_MOVE,	"move",		OT_OBJ,	OT_NUM,	OT_NUM,	0),
257   KTBL(ACT_SOUND,	"sound",	OT_SND,	0,	0,	0),
258   KTBL(ACT_TIMER,	"timer",	OT_TCH,	OT_NUM,	0,	0),
259   KTBL(ACT_RANDOMTIMER,	"randomtimer",	OT_TCH,	OT_NUM,	OT_NUM,	0),
260   KTBL(ACT_QUIT,	"quit",		0,	0,	0,	0),
261   KTBL(ACT_CHANGESET,	"changeset",	OT_SET,	0,	0,	0),
262   KTBL(ACT_CHANGECOL,	"changecol",	OT_COL,	0,	0,	0),
263   KTBL(ACT_TRANSPARENT,	"transparent",	OT_CEL,	OT_NUM,	0,	0),
264   KTBL(ACT_WINDOWSIZE,	"windowsize",	OT_NUM,	OT_NUM,	0,	0),
265   KTBL(ACT_VIEWPORT,	"viewport",	OT_NUM,	OT_NUM,	0,	0),
266   KTBL(ACT_IFFIXED,	"iffixed",	OT_OBJ,	OT_TCH,	OT_NUM,	0),
267   KTBL(ACT_IFNOTFIXED,	"ifnotfixed",	OT_OBJ,	OT_TCH,	OT_NUM,	0),
268   KTBL(ACT_IFMAPPED,	"ifmapped",	OT_CEL,	OT_TCH,	OT_NUM,	0),
269   KTBL(ACT_IFNOTMAPPED,	"ifnotmapped",	OT_CEL,	OT_TCH,	OT_NUM,	0),
270   KTBL(ACT_IFMOVED,	"ifmoved",	OT_OBJ,	OT_TCH,	OT_NUM,	0),
271   KTBL(ACT_IFNOTMOVED,	"ifnotmoved",	OT_OBJ,	OT_TCH,	OT_NUM,	0),
272   KTBL(ACT_SETFIX,	"setfix",	OT_OBJ,	OT_NUM,	0,	0),
273   KTBL(ACT_MOVEBYX,	"movebyx",	OT_OBJ,	OT_OBJ,	OT_NUM,	0),
274   KTBL(ACT_MOVEBYY,	"movebyy",	OT_OBJ,	OT_OBJ,	OT_NUM,	0),
275   KTBL(ACT_MOVETO,	"moveto",	OT_OBJ,	OT_NUM,	OT_NUM,	0),
276   KTBL(ACT_MOVERANDX,	"moverandx",	OT_OBJ,	OT_NUM,	OT_NUM,	0),
277   KTBL(ACT_MOVERANDY,	"moverandy",	OT_OBJ,	OT_NUM,	OT_NUM,	0),
278   KTBL(ACT_MOVETORAND,	"movetorand",	OT_OBJ,	0,	0,	0),
279   KTBL(ACT_MUSIC,	"music",	OT_SND,	0,	0,	0),
280   KTBL(ACT_NOTIFY,	"notify",	OT_STR,	0,	0,	0),
281   KTBL(-1, 		NULL,		0,	0,	0,	0)
282 };
283 
284 #define get_syntax(code) (event_syntax + ((code) & ~(BIT_EVENT|BIT_ACTION)))
285 
parse_keyword(str)286 int parse_keyword(str)
287      char *str;
288 {
289   KEYWORD_TABLE *p;
290 
291   for (p = event_syntax; p->n >= 0; p++) {
292     if (strcmp(str, p->str) == 0)
293       return p->n;
294   }
295   return -1;			/* keyword not found */
296 }
297 
298 
eval_env(str)299 char *eval_env(str)
300      char *str;			/* Caution! str destroyed */
301 {
302   char *p;
303   char *ep;
304   int mode;
305 
306   p = str;
307   mode = 0;
308   while (!mode && *p) {
309     switch (*p) {
310     case '-':
311     case '=':
312     case '+':
313     case '?':
314       mode = *p;
315     case ':':			/* Quick hack, no check ":str" */
316       *p = '\0';
317       /* FALL THROUGH */
318     default:
319       p++;
320       break;
321     }
322   }
323   ep = getenv(str);
324   switch (mode) {
325   case '=':
326     if (ep == NULL) {
327       ep = ks_strdup(p);
328       setenv(str, ep, 0);
329     }
330     break;
331   case '-':
332     if (ep == NULL)
333       ep = ks_strdup(p);
334     break;
335   case '+':
336     if (ep != NULL)
337       ep = ks_strdup(p);
338     break;
339   case '?':
340     if (ep == NULL) {
341       if (!*p)
342 	p = "parameter null or not set";
343       fprintf(stderr, "%s: %s: %s\n", *oargv, str, p);
344     }
345     break;
346   }
347   if (ep == NULL)
348     ep = "";
349   return ep;			/* Caution! Cannot to free this */
350 }
351 
352 /* parse_string - parse string
353  * str
354  *  >"hello\tworld Here we go!"
355  * buf (len = 8)
356  *   012345	67
357  *  >hello	w
358  *
359  * return malloced buffer address
360  *
361  * Analyze:
362  *  Heading quotation mark ("/! look quote_charset[])
363  *  '\' escaped character (\t \r \n \" \\)
364  *  $USER or ${USER} replaced to environment variable "USER"
365  *
366  */
parse_string(p,charset)367 char *parse_string(p, charset)
368      char **p;			/* string ptr to parse */
369      char *charset;		/* available character set (not quoted)
370 				 * (NULL:all)
371 				 */
372 {
373   int c;
374   int quote;			/* quote character (0:Not quoted) */
375   Bool escaped;			/* \ escaped flag */
376   Bool inkanji;			/* at Kanji 2nd byte flag */
377   int in_env, env_brace;
378   LSTR str;
379   LSTR env_name;
380   static char quote_charset[] = "\"/!";
381 
382   lstr_init(&str);
383   lstr_init(&env_name);
384   in_env = env_brace = 0;
385   inkanji = escaped = False;
386   quote = (**p && index(quote_charset, **p) != NULL) ? *(*p)++ : 0;
387   while ((c = **p) != '\0') {
388     ++*p;
389     if (escaped) {
390       switch (c) {
391       case 'n':			/* Newline */
392 	c = '\n';
393 	break;
394       case 'r':			/* CR */
395 	c = '\r';
396 	break;
397       case 't':			/* Tab */
398 	c = '\t';
399 	break;
400       default:			/* " or \ or $ */
401 	break;
402       }
403       escaped = False;
404     } else {
405       if (!inkanji) {
406 	if (c == '\\') {
407 	  escaped = True;	/* Escape character */
408 	  continue;
409 	}
410 	if (in_env) {
411 	  if ((env_brace && c == '}') || (!env_brace && !is_alnum(c) && c != '_')) {
412 	    in_env = 0;
413 	    lstr_cat(&str, eval_env(env_name.buf));
414 	    free(env_name.buf);
415 	    lstr_init(&env_name);
416 	    if (!env_brace)
417 	      lstr_ch(&str, c);
418 	    env_brace = 0;
419 	  } else {
420 	    lstr_ch(&env_name, c);
421 	  }
422 	  continue;
423 	}
424 	if (c == '$') {		/* Shell variable? */
425 	  in_env = 1;
426 	  if (**p == '{') {
427 	    ++*p;
428 	    env_brace = 1;
429 	  } else {
430 	    env_brace = 0;
431 	  }
432 	  continue;
433 	}
434 	if (quote) {
435 	  if (c == quote)
436 	    break;		/* quoted, terminated only quote char */
437 	} else {
438 	  if (charset != NULL && index(charset, c) == NULL)
439 	    break;
440 	}
441       }
442     }
443     lstr_ch(&str, c);
444     inkanji = inkanji ? 0 : is_sjis_1st(c & 0xff);
445   }
446   if (inkanji) {		/* Kanji 2nd byte? */
447     /* --*p; */
448     lstr_bs(&str);
449   }
450   if (in_env) {
451     lstr_cat(&str, eval_env(env_name.buf));
452     free(env_name.buf);
453   }
454   return str.buf;
455 }
456 
457 /*
458  * get token
459  * return malloced token buffer
460  */
get_token(p)461 char *get_token(p)
462      char **p;			/* string address to parse */
463 {
464   static char token_set[] =
465     "#-+/.0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
466 
467   while (**p && (**p != '"') && (index(token_set, **p) == NULL))
468     ++*p;
469   return parse_string(p, token_set);
470 }
471 
472 
addhit(c1,c2)473 void addhit(c1, c2)
474      int c1;
475      int c2;
476 {
477   int hn;
478   HITP *hp;
479   int i;
480 
481   hn = (cell+c1)->hitn;
482   hp = (cell+c1)->hitp;
483   for (i = 0; i < hn; i++) {
484     if ((hp + i)->n == c2)
485       return;
486   }
487   if (hp == NULL)
488     hp = (HITP *)ks_malloc(sizeof(*hp));
489   else
490     hp = (HITP *)ks_realloc(hp, (hn + 1) * sizeof(*hp));
491   (hp + hn)->n = c2;
492   (hp + hn)->s = 0;
493   (cell+c1)->hitn = ++hn;
494   (cell+c1)->hitp = hp;
495 }
496 
addobjhit(o1,o2)497 void addobjhit(o1, o2)
498      int o1;
499      int o2;
500 {
501   int hn;
502   HITP *hp;
503   int i;
504 
505   hn = (object+o1)->ohitn;
506   hp = (object+o1)->ohitp;
507   for (i = 0; i < hn; i++) {
508     if ((hp + i)->n == o2)
509       return;
510   }
511   if (hp == NULL)
512     hp = (HITP *)ks_malloc(sizeof(*hp));
513   else
514     hp = (HITP *)ks_realloc(hp, (hn + 1) * sizeof(*hp));
515   (hp + hn)->n = o2;
516   (hp + hn)->s = 0;
517   (object+o1)->ohitn = ++hn;
518   (object+o1)->ohitp = hp;
519 }
520 
init_hitck1(p)521 void init_hitck1(p)
522      EVT *p;
523 {
524   switch (p->evtype) {
525   case EVE_COLLIDE:
526   case EVE_APART:
527     if (p->eobj[0].type != OT_CEL) {
528       msg("W (%d) init_hitck: Not Cel '%s'!\n",
529 	  p->elineno, p->eobj[0].name);
530     } else if (p->eobj[1].type != OT_CEL) {
531       msg("W (%d) init_hitck: Not Cel '%s'!\n",
532 	  p->elineno, p->eobj[1].name);
533     } else {
534       addhit(p->eobj[0].no, p->eobj[1].no);
535       addhit(p->eobj[1].no, p->eobj[0].no);
536     }
537     break;
538   case EVE_IN:
539   case EVE_STILLIN:
540   case EVE_OUT:
541   case EVE_STILLOUT:
542     if (p->eobj[0].type != OT_OBJ) {
543       msg("W (%d) init_hitck: Not object '%s'!\n",
544 	  p->elineno, p->eobj[0].name);
545     } else if (p->eobj[1].type != OT_OBJ) {
546       msg("W (%d) init_hitck: Not object '%s'!\n",
547 	  p->elineno, p->eobj[1].name);
548     } else {
549       addobjhit(p->eobj[0].no, p->eobj[1].no);
550       addobjhit(p->eobj[1].no, p->eobj[0].no);
551     }
552     break;
553   }
554 }
555 
init_hitck()556 void init_hitck()
557 {
558   int i;
559   EVT *p;
560 
561   for (p = evtbl, i = 0; i < evn; p++, i++) {
562     init_hitck1(p);
563   }
564 }
565 
566 /* cnf_event - parse event description line in KISS configuration file
567  */
cnf_event(p,lineno)568 int cnf_event(p, lineno)
569      char *p;
570      int lineno;		/* cnf line number (from 1) */
571 {
572   int i, n, r;
573   char *token;
574   static EVT *evp = NULL;
575 
576   if (evtbl == NULL) {
577     if ( ! (evtbl = (EVT *)malloc(sizeof(EVT)*MAXEVENT)) ) {
578       msgset("E out of core while allocating %d bytes for %d events !\n",
579 	     sizeof(EVT)*MAXEVENT, MAXEVENT);
580     }
581     /* if we reach this point, all went fine */
582   }
583   r = 0;
584   while (*p) {
585     token = get_token(&p);
586     if (!*token) {
587       free(token);
588       break;
589     }
590     n = parse_keyword(token);
591     if (n < 0) {
592       msgset("W ``%s'' unknown keyword.\n", token);
593       free(token);
594       return -1;		/* keyword error */
595     }
596     free(token);
597     if (n & BIT_EVENT) {
598       if (evn >= WARN_EVENT) {
599 	msgset("W events over %d!\n", WARN_EVENT);
600 	r = -1;			/* event over error */
601       }
602       if (evn >= MAXEVENT) {
603         MAXEVENT++;
604         /* allocating enough core for 1 event more : */
605         if ( ! (evtbl = (EVT *)realloc(evtbl,sizeof(EVT)*MAXEVENT)) ) {
606 	  msgset("E out of core while allocating %d bytes for %d events !\n",
607 		 sizeof(EVT)*MAXEVENT, MAXEVENT);
608 	}
609 	/* if we reach this point, all went fine */
610       }
611       evp = evtbl + evn++;
612       evp->elineno = lineno;
613       evp->evtype = n;
614       for (i = 0; get_syntax(n)->argt[i]; i++) {
615 	evp->eobj[i].name = get_token(&p);
616       }
617       evp->actn = 0;
618       /* allocating core for exactly 1 action (the first) */
619       if ( ! (evp->act = (ACTION *)malloc(sizeof(ACTION))) ) {
620         msgset("E out of core while allocating %d bytes for 1 action !\n",
621                sizeof(ACTION));
622       }
623     } else if (n & BIT_ACTION) {
624       int atmp = 0;
625       ACTION	*ap_tmp	= NULL;
626       if ( !evp ) {
627         msgset("W action without an event.\n");
628         return -1;
629       }
630       atmp	= evp->actn + 2;
631       evp->alineno = lineno;
632       if (evp->actn >= WARN_ACTION) {
633 	msgset("W actions over %d!\n", WARN_ACTION);
634 	r = -1;			/* action over error */
635       }
636       if (evp->actn >= MAXACTION) {
637 	msgset("W actions over %d, action ignored!\n", MAXACTION);
638 	return -1;              /* no space to store action, abort! */
639       }
640       evp->act[evp->actn].n = n;
641       for (i = 0; get_syntax(n)->argt[i]; i++) {
642 	evp->act[evp->actn].aobj[i].name = get_token(&p);
643       }
644       /* allocating core for 1 action more */
645       ap_tmp = (ACTION *)realloc(evp->act,sizeof(ACTION)*atmp);
646       if ( ! ap_tmp ) {
647 	msgset( "E out of core while allocating %d bytes for %d actions !\n",
648 		sizeof(ACTION), atmp);
649       } else { /* this may be unneccesary, but I'm unsure and it doesn't hurt */
650 	evp->act = ap_tmp;
651       }
652       evp->actn++;
653       debug_printf("evp->actn=%d,\n", evp->actn);
654     }
655   }
656   return r;			/* return error code */
657 }
658 
get_named_sound(name)659 int get_named_sound(name)
660      char *name;
661 {
662   int i;
663 
664   for (i = 0; i < soundn; i++) {
665     if (strcmp(*(soundlist+i), name) == 0)
666     {
667       debug_printf("<SL:%d>\n", i);
668       return i;
669     }
670   }
671   for (i = 0; i < soundn; i++) {
672     if (strcmp_dos_filename(*(soundlist+i), name) == 0) {
673       if (warncase) {
674 	msg("W use sound file ``%s'' instead of ``%s''\n",
675 	    *(soundlist+i), name);
676       }
677       debug_printf("<SF:%s,%s>\n", *(soundlist+i),name);
678       return i;
679     }
680   }
681   return -1;			/* not found */
682 }
683 
get_named_cell(name)684 int get_named_cell(name)
685      char *name;
686 {
687   int i;
688 
689   for (i = 0; i < celcnt; i++) {
690     if (strcmp((cell+i)->filename, name) == 0)
691       return i;
692   }
693   for (i = 0; i < celcnt; i++) {
694     if (strcmp_dos_filename((cell+i)->filename, name) == 0) {
695       if (warncase) {
696         msg("W use cel file ``%s'' instead of ``%s''\n",
697 	    (cell+i)->filename, name);
698       }
699       return i;
700     }
701   }
702   return -1;			/* not found */
703 }
704 
705 /* return registrated objno */
regist_object(type,str,errorcode)706 int regist_object(type, str, errorcode)
707      int type;			/* object type */
708      char *str;
709      int *errorcode;		/* return error code */
710 {
711   int r;
712 
713   r = strtol(str, NULL, 0);
714   switch (type) {
715   case OT_SND:
716     if (soundn >= WARN_SOUNDFILE) {
717       msg("W sound files over %d!\n", WARN_SOUNDFILE);
718       *errorcode = 1;
719     }
720     if (soundn >= MAXSOUNDFILE) {
721       *errorcode = -1;
722       return -1;		/* sound file over error */
723     }
724     *(soundlist+soundn++) = ks_strdup(str);
725     return soundn-1;
726   case OT_TCH:
727 #if 0
728     if (r < 0 || r >= MAXTIMER) {
729       msg("W timer channel must be 0 to %d, ignoring timer channel %d !\n",
730           MAXTIMER, r);
731       *errorcode = r = -1;
732     }
733 #endif
734     if (r < 0 || r >= WARN_TIMER) {
735       msg("W timer channels over %d!\n", WARN_TIMER);
736       *errorcode = 1;
737     }
738     break;
739   case OT_SET:
740     if (r < 0 || r >= 10) {
741       msg("W set number must be 0 to %d!\n", setcnt-1);
742       msg("W ignore set number %d.\n", r);
743       *errorcode = r = -1;
744     }
745     break;
746   case OT_COL:
747     if (r < 0 || r >= 10) {
748       msg("W col number must be 0 to %d!\n", palcnt-1);
749       msg("W ignore col number %d.\n", r);
750       *errorcode = r = -1;
751     }
752     break;
753   case OT_NUM:
754   case OT_STR:
755     break;
756   default:
757     *errorcode = r = -1;	/* error */
758   }
759   return r;
760 }
761 
762 /* return error code
763  *   == 0 : no error
764  *   >  0 : warning
765  *   <  0 : error
766  */
parse_argument(p,str,rtype)767 int parse_argument(p, str, rtype)
768      EVOBJ *p;			/* p->type, p->no update */
769      char *str;
770      int rtype;			/* default type */
771 {
772   int r;
773 
774   r = 0;
775   if (rtype != OT_STR) {
776     switch(*str) {
777     case '#':
778       p->type = OT_OBJ;
779       p->no = strtol(str+1, NULL, 10);
780       break;
781     default:
782       p->type = OT_CEL;
783       p->no = get_named_cell(str);
784       if (p->no < 0) {
785 	p->type = OT_SND;
786 	p->no = get_named_sound(str);
787       }
788       break;
789     }
790   }
791   if (p->no < 0) {
792     p->type = rtype;
793     p->no = regist_object(rtype, str, &r);
794     sprintf(G_ERRbuf,"''%s'' is not part of any object", str);
795     debug_printf(" obj(%d,%d)=[%s]", p->type, p->no, str);
796     if (p->no < 0 && rtype != OT_NUM && rtype != OT_STR)
797       p->type = -1;
798   } else {
799     debug_printf(" obj(%d,%d)", p->type, p->no);
800   }
801   return r;
802 }
803 
804 /* return : line number error detected (0 no error) */
compile_event(n)805 int compile_event(n)
806      int n;
807 {
808   int j, k;
809   int r, errline;
810   EVT *ep;
811   ACTION *ap;
812 
813   if (!n) {
814     /* first line allocate work area */
815     soundlist = (char **)ks_malloc(sizeof(char *)*MAXSOUNDFILE);
816     timertbl = (TIMER *)ks_malloc(sizeof(TIMER)*MAXTIMER);
817     timertbln = MAXTIMER;
818     active_timer = 0;
819     /* reset all timers */
820     bzero((char *)timertbl, sizeof(TIMER)*MAXTIMER);
821   }
822   ep = evtbl + n;
823   debug_printf("%6d,%6d:\tevent %d: %s(",
824 	       ep->elineno, ep->alineno, n, get_syntax(ep->evtype)->str);
825   errline = 0;			/* reset error line */
826   for (j = 0; get_syntax(ep->evtype)->argt[j]; j++) {
827     debug_printf("%s%s", !j?"":",", ep->eobj[j].name);
828     r = parse_argument(&ep->eobj[j], ep->eobj[j].name,
829 		       get_syntax(ep->evtype)->argt[j]);
830     if (r && ep->eobj[j].type != OT_NUM && ep->eobj[j].type != OT_STR) {
831       errline = ep->elineno;
832       if (r < 0) {
833 	ep->evtype = 0;		/* ignore this event */
834 	return errline;		/* abort compile */
835       }
836     }
837   }
838   debug_printf(").\n");
839 
840   for (ap = ep->act, j = 0; j < ep->actn; ap++, j++) {
841     debug_printf("%6d,%6d:\t  action %d: %s(",
842 		 ep->elineno, ep->alineno, j, get_syntax(ap->n)->str);
843     for (k = 0; get_syntax(ap->n)->argt[k]; k++) {
844       debug_printf("%s%s", !k?"":",", ap->aobj[k].name);
845       r = parse_argument(&ap->aobj[k], ap->aobj[k].name,
846 			 get_syntax(ap->n)->argt[k]);
847       if (r < 0 && ! debug_mode)
848         msg("W (somewhere between line%6d and line%6d)\n\t\t%s!\n",
849             ep->elineno, ep->alineno, G_ERRbuf);
850       if (r && ap->aobj[k].type != OT_NUM && ap->aobj[k].type != OT_STR) {
851 	errline = ep->alineno;
852 	if (r < 0)
853 	  ap->n = ACT_NOP;	/* ignore this action */
854       }
855     }
856     debug_printf(").\n");
857   }
858   return errline;
859 }
860 
init_redraw_area(evw)861 void init_redraw_area(evw)
862      EVW *evw;
863 {
864   evw->redraw_xtop = imgw;
865   evw->redraw_ytop = imgh;
866   evw->redraw_xend = evw->redraw_yend = 0;
867 }
868 
add_redraw_area(evw,x,y,w,h)869 void add_redraw_area(evw, x, y, w, h)
870      EVW *evw;
871      int x;
872      int y;
873      int w;
874      int h;
875 {
876   if (x < evw->redraw_xtop)
877     evw->redraw_xtop = x;
878   if (y < evw->redraw_ytop)
879     evw->redraw_ytop = y;
880   if (x + w > evw->redraw_xend)
881     evw->redraw_xend = x + w;
882   if (y + h > evw->redraw_yend)
883     evw->redraw_yend = y + h;
884 }
885 
update_redraw_area(evw)886 void update_redraw_area(evw)
887      EVW *evw;
888 {
889   int w, h;
890 
891   w = evw->redraw_xend - evw->redraw_xtop;
892   h = evw->redraw_yend - evw->redraw_ytop;
893   if (w > 0 && h > 0)
894     redraw_cells(evw->redraw_xtop, evw->redraw_ytop, w, h);
895 }
896 
delete_timer(ch)897 void delete_timer(ch)
898      int ch;
899 {
900   int i, n;
901   TIMER *p;
902 
903   for (p = timertbl, i = 0; i < active_timer; p++, i++) {
904     if (p->channel == ch) {
905       n = active_timer - i - 1;
906       if (n > 0) {
907 	bcopy(p+1, p, sizeof(*p)*n);
908       }
909       --active_timer;
910       break;
911     }
912   }
913 }
914 
915 /* set timer
916  * starttime = tm0 - event_delay
917  */
set_timer(evw,ch,n)918 void set_timer(evw, ch, n)
919      EVW *evw;
920      int ch;
921      int n;
922 {
923   int i;
924   TIMER *p;
925   TIMER tm;
926 
927   delete_timer(ch);
928   if (n == 0 && !wkiss_bug_emulation)
929     return;
930 
931   bcopy(&evw->tm0, &tm.starttime, sizeof(struct TMV));
932   add_time(&tm.starttime, -evw->event_delay);
933   bcopy(&tm.starttime, &tm.alarmtime, sizeof(struct TMV));
934   add_time(&tm.alarmtime, n);
935 
936   if (active_timer >= timertbln) {
937     timertbln++;
938     timertbl = (TIMER *)ks_realloc(timertbl, sizeof(TIMER)*timertbln);
939   }
940   for (p = timertbl, i = 0; i < active_timer; p++, i++) {
941     if (diff_time(&p->alarmtime, &tm.alarmtime) > 0)
942       break;
943   }
944   i = active_timer - i;
945   if (i > 0) {
946     bcopy(p, p+1, sizeof(TIMER)*i);
947   }
948   bcopy(&tm, p, sizeof(TIMER));
949   p->channel = ch;
950   active_timer++;
951 }
952 
953 /* change cell mapping status
954  * return  0: No need to update image
955  */
change_cel_mapping0(evw,p,status)956 int change_cel_mapping0(evw, p, status)
957      EVW *evw;
958      CELL *p;
959      int status;
960 {
961   int n;
962 
963   switch (status) {
964   case ACT_UNMAP:		/* unmap */
965     if (p->unmap)
966       return 0;			/* already unmapped */
967     p->unmap = 1;
968     break;
969   case ACT_MAP:			/* map */
970     if (!p->unmap)
971       return 0;			/* already mapped */
972     p->unmap = 0;
973     break;
974   case ACT_ALTMAP:		/* altmap */
975     p->unmap ^= 1;
976     break;
977   default:			/* ??? unknown mode ??? */
978     return 0;
979   }
980   debug_printf("! %s [%s] !\n", p->unmap ? "unmap" : "map", p->filename);
981   if (!p->setflag[cset])
982     return 0;			/* no need to update image */
983   n = p->obj;
984   add_redraw_area(evw,
985 		  (kset[cset].obj+n)->x + p->ofsx,
986 		  (kset[cset].obj+n)->y + p->ofsy,
987 		  p->width, p->height);
988   return 1;			/* cel mapping status is changed! */
989 }
990 
change_cel_mapping(p,status)991 int change_cel_mapping(p, status)
992      CELL *p;
993      int status;
994 {
995   EVW evw;
996   int r;
997 
998   init_redraw_area(&evw);
999   r = change_cel_mapping0(&evw, p, status);
1000   update_redraw_area(&evw);
1001   return r;
1002 }
1003 
change_aobj_mapping(evw,p,status)1004 int change_aobj_mapping(evw, p, status)
1005      EVW *evw;
1006      EVOBJ *p;
1007      int status;
1008 {
1009   int i, r;
1010 
1011   r = 0;
1012   switch(p->type) {
1013   case OT_CEL:
1014     r = change_cel_mapping0(evw, cell+p->no, status);
1015     break;
1016   case OT_OBJ:
1017     for (i = 0; i < celcnt; i++)
1018       if ((cell+i)->obj == p->no)
1019 	r |= change_cel_mapping0(evw, cell+i, status);
1020     break;
1021   default:
1022     msg("W change_aobj_mapping: type %d cannot to change mapping\n", p->type);
1023     break;
1024   }
1025   return r;
1026 }
1027 
1028 /* change cell transparency level
1029  * return  0: No need to update image
1030  */
change_cel_transparency(evw,p,d)1031 int change_cel_transparency(evw, p, d)
1032      EVW *evw;
1033      CELL *p;
1034      int d;			/* transparency add value */
1035 {
1036   int n;
1037 
1038   n = p->transparency + d;
1039   if (n < 0)
1040     n = 0;
1041   else if (n > 256)
1042     n = 256;
1043   if (n == p->transparency)
1044     return 0;			/* transparency level is not changed! */
1045   debug_printf("! transparency [%s] %d -> %d !\n",
1046 	       p->filename, p->transparency, n);
1047   if (p->clip == 0) {
1048     p->transparency = n;
1049     return 0;                   /* just set transparency.  transclip */
1050   }                             /* will be set after we load clip */
1051   set_transparency(p, n);
1052   if (!p->setflag[cset] || p->unmap)
1053     return 0;			/* no need to update image */
1054   add_redraw_area(evw,
1055 		  (kset[cset].obj+p->obj)->x + p->ofsx,
1056 		  (kset[cset].obj+p->obj)->y + p->ofsy,
1057 		  p->width, p->height);
1058   return 1;			/* cel mapping status is changed! */
1059 }
1060 
change_aobj_transparency(evw,p,n)1061 int change_aobj_transparency(evw, p, n)
1062      EVW *evw;
1063      EVOBJ *p;
1064      int n;
1065 {
1066   int i, r;
1067 
1068   r = 0;
1069   switch(p->type) {
1070   case OT_CEL:
1071     r = change_cel_transparency(evw, cell+p->no, n);
1072     break;
1073   case OT_OBJ:
1074     for (i = 0; i < celcnt; i++)
1075       if ((cell+i)->obj == p->no)
1076 	r |= change_cel_transparency(evw, cell+i, n);
1077     break;
1078   default:
1079     msg("W change_aobj_transparency: type %d cannot to change transparency\n", p->type);
1080     break;
1081   }
1082   return r;
1083 }
1084 
cond_set_timer(evw,ap)1085 void cond_set_timer(evw, ap)
1086      EVW *evw;
1087      ACTION *ap;
1088 {
1089   int f;
1090 
1091   f = 0;
1092   switch (ap->n) {
1093   case ACT_IFMOVED:
1094     f = ((kset[cset].obj+ap->aobj[0].no)->x !=
1095 	 (kset[cset].obj+ap->aobj[0].no)->ox ||
1096 	 (kset[cset].obj+ap->aobj[0].no)->y !=
1097 	 (kset[cset].obj+ap->aobj[0].no)->oy);
1098     break;
1099   case ACT_IFNOTMOVED:
1100     f = ((kset[cset].obj+ap->aobj[0].no)->x ==
1101 	 (kset[cset].obj+ap->aobj[0].no)->ox &&
1102 	 (kset[cset].obj+ap->aobj[0].no)->y ==
1103 	 (kset[cset].obj+ap->aobj[0].no)->oy);
1104     break;
1105   case ACT_IFFIXED:
1106     f = ((object + ap->aobj[0].no)->pesi >= (object + ap->aobj[0].no)->fix);
1107     break;
1108   case ACT_IFNOTFIXED:
1109     f = ((object + ap->aobj[0].no)->pesi < (object + ap->aobj[0].no)->fix);
1110     break;
1111   case ACT_IFMAPPED:
1112     f = !(cell + ap->aobj[0].no)->unmap;
1113     break;
1114   case ACT_IFNOTMAPPED:
1115     f = (cell + ap->aobj[0].no)->unmap;
1116     break;
1117   }
1118   if (!f)
1119     return;
1120 
1121   set_timer(evw, ap->aobj[1].no, ap->aobj[2].no);
1122   debug_printf("! %s(%d,%d,%d) ",
1123 	       get_syntax(ap->n)->str,
1124 	       ap->aobj[0].no, ap->aobj[1].no, ap->aobj[2].no);
1125   if (ap->aobj[2].no)
1126     debug_printf("%.19s.%06ld ",
1127 		 ctime(&(timertbl+ap->aobj[1].no)->starttime.tv_sec),
1128 		 (timertbl+ap->aobj[1].no)->starttime.tv_usec);
1129   debug_printf(" !\n");
1130 }
1131 
act_move(evw,ap)1132 int act_move(evw, ap)
1133      EVW *evw;
1134      ACTION *ap;
1135 {
1136   int x, y;
1137   int n, r;
1138   int i;
1139   EVHITWK hit;
1140   AREA ar;
1141   extern EVHITWK mouse_move_hit; /* fkiss.c */
1142   extern int moving_object;	/* fkiss.c */
1143   int mo;
1144 
1145   r = 0;
1146   n = ap->aobj[0].no;
1147   if (ap->aobj[0].type == OT_CEL)
1148     n = (cell+n)->obj;
1149   mo = moving_object;
1150   if (mo >= 0) {
1151     moving_object = -1;
1152     move_object_end(&mouse_move_hit);
1153   }
1154   move_object_start(&hit, n);
1155   x = (kset[cset].obj+n)->x;
1156   y = (kset[cset].obj+n)->y;
1157   switch (ap->n) {
1158   case ACT_MOVE:
1159     x += ap->aobj[1].no;
1160     y += ap->aobj[2].no;
1161     break;
1162   case ACT_MOVEBYX:
1163     x = (kset[cset].obj+ap->aobj[1].no)->x + ap->aobj[2].no;
1164     break;
1165   case ACT_MOVEBYY:
1166     y = (kset[cset].obj+ap->aobj[1].no)->y + ap->aobj[2].no;
1167     break;
1168   case ACT_MOVETO:
1169     x = ap->aobj[1].no;
1170     y = ap->aobj[2].no;
1171     break;
1172   case ACT_MOVERANDX:
1173     i = ap->aobj[2].no - ap->aobj[1].no ;
1174     if (i > 0)
1175       x += ap->aobj[1].no + ks_rand() % (i+1);
1176     break;
1177   case ACT_MOVERANDY:
1178     i = ap->aobj[2].no - ap->aobj[1].no;
1179     if (i > 0)
1180       y += ap->aobj[1].no + ks_rand() % (i+1);
1181     break;
1182   case ACT_MOVETORAND:
1183     i = imgw - (object+n)->width;
1184     if (i > 0)
1185       x = ks_rand() % (i+1);
1186     i = imgh - (object+n)->height;
1187     if (i > 0)
1188       y = ks_rand() % (i+1);
1189     break;
1190   }
1191   if (move_object2(n, x, y,&ar)) {
1192     add_redraw_area(evw, ar.x, ar.y, ar.w, ar.h);
1193     r |= ACTBIT_MAP;
1194     debug_printf("! %s(%d,%d,%d) !\n", get_syntax(ap->n)->str, n, x, y);
1195   }
1196   move_object_end(&hit);
1197   if (mo >= 0) {
1198     move_object_start(&mouse_move_hit, mo);
1199     moving_object = mo;
1200   }
1201   return r;
1202 }
1203 
1204 /*
1205  * return changed status infrmation bits
1206  * ACTBIT_SOUND:on sound played
1207  * ACTBIT_MAP:on cell mapping status changed, need to update image
1208  */
event_action(evw,p,r)1209 int event_action(evw, p, r)
1210      EVW *evw;
1211      EVT *p;
1212      int r;
1213 {
1214   int i, n;
1215   int mapping_action;
1216   int newset, newcol;
1217   int w, h;
1218   ACTION *ap;
1219 
1220   newset = newcol = -1;
1221   for (ap = p->act, i = 0; i < p->actn; ap++, i++) {
1222     n = mapping_action = 0;
1223     switch(ap->n) {
1224     case ACT_MUSIC:
1225     case ACT_SOUND:
1226       debug_printf("! sound(%s) !\n", *(soundlist+ap->aobj[0].no));
1227       bg_play(*(soundlist+ap->aobj[0].no));
1228       r |= ACTBIT_SOUND;
1229       break;
1230     case ACT_MAP:
1231     case ACT_UNMAP:
1232     case ACT_ALTMAP:
1233       mapping_action = ap->n;
1234       break;
1235     case ACT_CHANGESET:
1236       newset = ap->aobj[0].no;
1237       break;
1238     case ACT_CHANGECOL:
1239       newcol = ap->aobj[0].no;
1240       break;
1241     case ACT_RANDOMTIMER:
1242       if (ap->aobj[1].no && ap->aobj[2].no)
1243 	n = ks_rand() % ap->aobj[2].no;
1244       /* FALL THROUGH */
1245     case ACT_TIMER:
1246       n += ap->aobj[1].no;
1247       set_timer(evw, ap->aobj[0].no, n);
1248       debug_printf("! timer(%d,%d) ", ap->aobj[0].no, n);
1249       if (n)
1250 	debug_printf("%.19s.%06ld ",
1251 		     ctime(&(timertbl+ap->aobj[0].no)->starttime.tv_sec),
1252 		     (timertbl+ap->aobj[0].no)->starttime.tv_usec);
1253       debug_printf(" !\n");
1254       break;
1255     case ACT_IFMOVED:
1256     case ACT_IFNOTMOVED:
1257     case ACT_IFFIXED:
1258     case ACT_IFNOTFIXED:
1259     case ACT_IFMAPPED:
1260     case ACT_IFNOTMAPPED:
1261       cond_set_timer(evw, ap);
1262       break;
1263     case ACT_SETFIX:
1264       debug_printf("! setfix(%d,%d) !\n", ap->aobj[0].no, ap->aobj[1].no);
1265       (object + ap->aobj[0].no)->fix = ap->aobj[1].no;
1266       /* (object + ap->aobj[0].no)->pesi = 0; */
1267       if (!ap->aobj[1].no) {
1268 	kissevent_handler2(EVE_UNFIX, ap->aobj[0].no, 1);
1269       }
1270       break;
1271     case ACT_MOVE:
1272     case ACT_MOVEBYX:
1273     case ACT_MOVEBYY:
1274     case ACT_MOVETO:
1275     case ACT_MOVERANDX:
1276     case ACT_MOVERANDY:
1277     case ACT_MOVETORAND:
1278       r |= act_move(evw, ap);
1279       break;
1280     case ACT_TRANSPARENT:
1281       debug_printf("! transparent(%d,%d) !\n", ap->aobj[0].no, ap->aobj[1].no);
1282       if (change_aobj_transparency(evw, &ap->aobj[0], ap->aobj[1].no))
1283 	r |= ACTBIT_MAP;
1284       break;
1285     case ACT_WINDOWSIZE:
1286       debug_printf("! windowsize(%d,%d) !\n", ap->aobj[0].no, ap->aobj[1].no);
1287       w = topw + ap->aobj[0].no;
1288       if (w < 1)
1289 	w = 1;
1290       h = toph + ap->aobj[1].no;
1291       if (h < 1)
1292 	h = 1;
1293       XResizeWindow(dsp, topwin, w, h);
1294       break;
1295     case ACT_VIEWPORT:
1296       debug_printf("! viewport(%d,%d) !\n", ap->aobj[0].no, ap->aobj[1].no);
1297       scrdx = -ap->aobj[0].no;
1298       scrdy = -ap->aobj[1].no;
1299       break;
1300     case ACT_SHELL:
1301       debug_printf("! shell(%s) !\n", ap->aobj[0].name);
1302       if (enable_event_shell)
1303 	bg_shell(ap->aobj[0].name);
1304       break;
1305     case ACT_NOTIFY:
1306       debug_printf("! notify(%s) !\n", ap->aobj[0].name);
1307       fputs(ap->aobj[0].name, stderr);
1308       break;
1309     case ACT_DEBUG:
1310       debug_printf("! debug(%s) !\n", ap->aobj[0].name);
1311       fputs(ap->aobj[0].name, stderr);
1312       break;
1313     case ACT_QUIT:
1314       debug_printf("! quit !\n");
1315       change_menu_func(1);	/* Quit */
1316       break;
1317     default:
1318       break;
1319     }
1320     if (mapping_action) {
1321       /* EVHITWK hit; */
1322 
1323       n = ap->aobj[0].no;
1324       if (ap->aobj[0].type == OT_CEL)
1325 	n = (cell + n)->obj;
1326       /* move_object_start(&hit, n); */
1327       if (change_aobj_mapping(evw, &ap->aobj[0], mapping_action)) {
1328 	r |= ACTBIT_MAP;
1329       }
1330       /* move_object_end(&hit); */
1331     }
1332   }
1333   if (newset != -1 || newcol != -1)
1334     change_setpal(newset, newcol);
1335   return r;
1336 }
1337 
1338 
handler_sub(evw,type,arg,arg2)1339 int handler_sub(evw, type, arg, arg2)
1340      EVW *evw;
1341      int type;
1342      int arg;
1343      int arg2;
1344 {
1345   int i, r, n;
1346   int f, noredraw;
1347   EVT *ep;
1348 
1349   debug_printf("event: %s, arg: %d,%d at %.19s.%06ld\n",
1350 	       get_syntax(type)->str, arg, arg2,
1351 	       ctime(&evw->tm0.tv_sec), evw->tm0.tv_usec);
1352   init_redraw_area(evw);
1353   r = noredraw = 0;
1354   for (ep = evtbl, i = 0; i < evn; ep++, i++) {
1355     if (ep->evtype != type)
1356       continue;			/* no match, check next */
1357     n = arg;
1358 #if 0
1359     /* EMK's changes */
1360     if (type == EVE_SET || type == EVE_COL)
1361       noredraw = 1;
1362 #endif
1363     switch (type) {
1364     case EVE_INITIALIZE:
1365       noredraw = 1;
1366       /* FALL THROUGH */
1367     case EVE_BEGIN:
1368     case EVE_END:
1369       f = 1;
1370       break;
1371     case EVE_UNFIX:
1372       if (arg2) {
1373 	f = (ep->eobj[0].type == OT_OBJ && ep->eobj[0].no == n);
1374 	break;
1375       }
1376       /* FALL THROUGH */
1377     case EVE_PRESS:
1378     case EVE_RELEASE:
1379     case EVE_CATCH:
1380     case EVE_DROP:
1381     case EVE_FIXCATCH:
1382     case EVE_FIXDROP:
1383       if (ep->eobj[0].type == OT_OBJ && n >= 0)
1384 	n = (cell+n)->obj;
1385       /* FALL THROUGH */
1386     case EVE_ALARM:
1387     case EVE_SET:
1388     case EVE_COL:
1389       f = (n == ep->eobj[0].no);
1390       break;
1391     case EVE_VERSION:
1392       f = (n >= ep->eobj[0].no);
1393       break;
1394     case EVE_COLLIDE:
1395     case EVE_APART:
1396     case EVE_IN:
1397     case EVE_STILLIN:
1398     case EVE_OUT:
1399     case EVE_STILLOUT:
1400       f = (n == ep->eobj[0].no && arg2 == ep->eobj[1].no)
1401 	|| (n == ep->eobj[1].no && arg2 == ep->eobj[0].no);
1402       break;
1403     default:			/* others, Not implemented */
1404       f = 0;
1405       break;
1406     }
1407     if (f)
1408       r |= event_action(evw, ep, r);
1409   }
1410   if (r & ACTBIT_MAP && !noredraw) /* cell mapping status changed? */
1411     update_redraw_area(evw);
1412   return r;
1413 }
1414 
kissevent_handler2(type,arg,arg2)1415 int kissevent_handler2(type, arg, arg2)
1416      int type;
1417      int arg;
1418      int arg2;
1419 {
1420   EVW evw;
1421 
1422   if (!event_ok)
1423     return 0;
1424   current_time(&evw.tm0);
1425   evw.event_delay = 0;
1426   return handler_sub(&evw, type, arg, arg2);
1427 }
1428 
kissevent_handler(type,arg)1429 int kissevent_handler(type, arg)
1430      int type;
1431      int arg;
1432 {
1433   return kissevent_handler2(type, arg, 0);
1434 }
1435 
1436 /* initialise random seed */
init_rand()1437 void init_rand()
1438 {
1439   int i;
1440   struct TMV tm0;
1441 
1442   i = randseed;
1443   if (!i) {
1444     current_time(&tm0);
1445     i = tm0.tv_sec;
1446   }
1447   ks_srand(i);
1448 }
1449 
1450 typedef struct {
1451   long filesize;
1452   char *pathname;
1453 } SOUND_SORT_TABLE;
1454 
sound_cache_prio(p0,p1)1455 int sound_cache_prio(p0, p1)
1456      SOUND_SORT_TABLE *p0;
1457      SOUND_SORT_TABLE *p1;
1458 {
1459   return p0->filesize - p1->filesize;
1460 }
1461 
1462 /* preload sound data to cache buffer
1463  * from small to big size sound file
1464  */
preload_sound_cache()1465 void preload_sound_cache()
1466 {
1467   int i;
1468   SOUND_SORT_TABLE *sstbl, *p;
1469   long total;
1470   char *buf;
1471 
1472   if (!sound_mode)
1473     return;
1474   /* check True sound file name */
1475   for (i = 0; i < soundn; i++) {
1476     buf = ks_filename(*(soundlist+i));
1477     if (buf) {
1478       free(*(soundlist+i));
1479       *(soundlist+i) = buf;
1480     }
1481   }
1482   sstbl = (SOUND_SORT_TABLE *)malloc(sizeof(SOUND_SORT_TABLE) * soundn);
1483   if (sstbl == NULL)
1484     return;
1485   for (p = sstbl, i = 0; i < soundn; p++, i++) {
1486     p->pathname = *(soundlist+i);
1487     p->filesize = sound_filesize(*(soundlist+i));
1488   }
1489   qsort(sstbl, soundn, sizeof(SOUND_SORT_TABLE), sound_cache_prio);
1490   total = 0;
1491   for (p = sstbl, i = 0; i < soundn; p++, i++) {
1492     if (p->filesize < 0)
1493       continue;			/* unknown size, ignore */
1494     if (total + p->filesize > sound_cache_limit)
1495       break;			/* total size over limit! */
1496     if (sound_cache(p->pathname) >= 0) {
1497       debug_printf("preload sound file ``%s''\t(%8ld bytes).\n",
1498 		   p->pathname, p->filesize);
1499       total += p->filesize;
1500     }
1501   }
1502   debug_printf("preloaded sound total %8ld bytes (limit %8ld bytes).\n",
1503 	       total, sound_cache_limit);
1504   free(sstbl);
1505 }
1506 
kissevent_initialize()1507 int kissevent_initialize()
1508 {
1509   init_rand();
1510   preload_sound_cache();
1511   event_ok = True;
1512   kissevent_handler(EVE_INITIALIZE, 0);
1513   return 0;
1514 }
1515 
kissevent_timer()1516 void kissevent_timer()
1517 {
1518   int i, ch;
1519   EVW evw;
1520 
1521   if (!event_ok || !active_timer)
1522     return;			/* active timer channel is not exist */
1523   current_time(&evw.tm0);
1524   for (i = 0; i < active_timer; i++) {
1525     evw.event_delay = diff_time(&evw.tm0, &(timertbl+i)->alarmtime);
1526     if (evw.event_delay >= 0) {
1527       debug_printf("event_delay = %ld\n", evw.event_delay);
1528       ch = (timertbl+i)->channel;
1529       /* reset timer */
1530       delete_timer(ch);
1531       handler_sub(&evw, EVE_ALARM, ch, 0);
1532       break;
1533     }
1534   }
1535 }
1536 
get_sleep_time()1537 int get_sleep_time()
1538 {
1539   int i, r;
1540   long lefttime;
1541   TIMER *p;
1542   struct TMV tm0;
1543 
1544   r = sleep_tick;
1545   if (!event_ok || !active_timer)
1546     return r;			/* active timer channel is not exist */
1547   current_time(&tm0);
1548   for (p = timertbl, i = 0; i < active_timer; p++, i++) {
1549     lefttime = diff_time(&p->alarmtime, &tm0);
1550     if (lefttime < 0)
1551       return 0;			/* time over! Don't sleep */
1552     if (r > lefttime)
1553       r = lefttime;
1554   }
1555   return r;
1556 }
1557 
1558 /* End of file */
1559