2 * xhextris Copyright 1990 David Markley, dm3e@+andrew.cmu.edu, dam@cs.cmu.edu
4 * Permission to use, copy, modify, and distribute, this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders be used in
9 * advertising or publicity pertaining to distribution of the software with
10 * specific, written prior permission, and that no fee is charged for further
11 * distribution of this software, or any modifications thereof. The copyright
12 * holder make no representations about the suitability of this software for
13 * any purpose. It is provided "as is" without express or implied warranty.
15 * THE COPYRIGHT HOLDER DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA, PROFITS, QPA OR GPA, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
20 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
24 /* This file contains the X I/O handling routines for hextris.
30 #include <X11/Xutil.h>
31 #include <X11/keysym.h>
32 #include <sys/types.h>
43 /* Macros to make 4.2 BSD select compatible with 4.3 BSD select */
46 #define FD_SET(fd,fdset) (*(fdset) |= (1<<(fd)))
47 #define FD_CLR(fd,fdset) (*(fdset) &= ~(1<<(fd)))
48 #define FD_ISSET(fd, fdset) (*(fdset) & (1<<(fd)))
49 #define FD_ZERO(fdset) (*(fdset) = 0)
52 /* I dislike global variables, but this made it much simpler */
57 XFontStruct
*font_info
, *hexfont_info
;
59 XColor Orange1
, Red1
, Blue1
, Green1
, Yellow1
, Chocolate1
, Purple1
,
60 SteelBlue1
, Black
, White
, Plum1
, Maroon1
, Pink1
, Wheat
;
61 XColor Orange4
, Red4
, Blue4
, Green4
, Yellow4
, Chocolate4
, Purple4
, SteelBlue4
,
62 Plum4
, Maroon4
, Pink4
, DarkSlateGrey
;
67 /* This is the big, ugly main X procedure...
74 int width
, height
, i
, bufsize
=20, inverse
=0, pleasure
=0, window_size
= 0;
75 XSizeHints size_hints
;
78 XComposeStatus compose
;
79 struct timeval tp
, ltp
;
81 double intvl
= 0, newintvl
;
84 /* The following variables are required by hextris */
85 int score
= 0, rows
= 0, game_over
= 1, game_view
= 1, oldscore
= 0;
87 high_score_t high_scores
[MAXHIGHSCORES
];
88 position_t grid
[MAXROW
][MAXCOLUMN
];
89 piece_t npiece
, piece
;
90 char *name
, *log_name
;
95 pwent
= getpwuid(PlayerUID
);
96 if (pwent
== (struct passwd
*) NULL
) {
97 if ((log_name
= (char *)getenv("USER")) == NULL
)
100 log_name
= pwent
->pw_name
;
102 pwent
= getpwuid(getuid());
103 if (pwent
== (struct passwd
*) NULL
) {
104 if ((log_name
= (char *)getenv("USER")) == NULL
)
107 log_name
= pwent
->pw_name
;
109 for (i
= 1; i
< argc
; i
++) {
110 if (! strcmp(argv
[i
],"-rv")) {
114 if (! strcmp(argv
[i
],"-p"))
117 if ((name
= (char *)getenv("XHEXNAME")) == NULL
)
119 printf("\nWelcome, %s...\n",name
);
120 gettimeofday(&tp
, &tzp
);
121 srandom((int)(tp
.tv_usec
));
123 strcpy(log_message
,log_name
);
124 strcat(log_message
,"\t");
125 strcat(log_message
,SYS_NAME
);
126 strcat(log_message
,"\t1.00");
128 set_up_display(inverse
);
129 set_up_window(&width
,&height
,&size_hints
,argv
,argc
);
136 intvl
= 100000+(200000-((rows
> 40) ? 20 : (rows
/2))*10000);
139 if ((game_over
= update_drop(grid
,&npiece
,&piece
,&score
,&rows
))) {
140 read_high_scores(high_scores
);
141 if (is_high_score(name
, log_name
, score
, rows
, high_scores
))
142 write_high_scores(high_scores
,log_name
);
143 read_high_scores(high_scores
);
145 if (score
!= oldscore
) {
149 gettimeofday(<p
, NULL
);
151 gettimeofday(&tp
, NULL
);
152 newintvl
= intvl
- (((tp
.tv_sec
- ltp
.tv_sec
)*1000000)+
153 (tp
.tv_usec
- ltp
.tv_usec
));
157 tp
.tv_usec
= newintvl
;
159 FD_SET(ConnectionNumber(display
),&fdst
);
160 select(ConnectionNumber(display
)+1,&fdst
,0,0,&tp
);
161 while (XPending(display
)) {
162 XNextEvent(display
, &report
);
163 switch (report
.type
) {
165 while (XCheckTypedEvent(display
, Expose
, &report
));
168 redraw_game(grid
,&npiece
,&piece
,&score
,&rows
,game_view
,
171 case ConfigureNotify
:
172 while (XCheckTypedEvent(display
,ConfigureNotify
,&report
));
173 width
= report
.xconfigure
.width
;
174 height
= report
.xconfigure
.height
;
175 if ((width
< size_hints
.min_width
) ||
176 (height
< size_hints
.min_height
))
180 redraw_game(grid
,&npiece
,&piece
,&score
,&rows
,game_view
,
191 XLookupString(&(report
.xkey
), buffer
, bufsize
, &key
, &compose
);
209 do_choice(buffer
,grid
,&npiece
,&piece
,&score
,&rows
,
210 &game_over
, &game_view
, high_scores
);
211 if ((score
!= oldscore
) || (! score
)) {
214 gettimeofday(<p
, NULL
);
225 /* This sets up the basic connections to the X server, the fonts, and
226 * which colors are to be foreground and background.
228 set_up_display(inverse
)
233 if ( (display
= XOpenDisplay(NULL
)) == NULL
) {
234 fprintf(stderr
, "xhextris: cannot connect to X server.\n");
237 screen
= DefaultScreen(display
);
238 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
239 "red4", &Red4
, &Red4
);
240 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
241 "green4", &Green4
, &Green4
);
242 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
243 "black", &Black
, &Black
);
244 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
245 "white", &White
, &White
);
246 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
247 "Orange4", &Orange4
, &Orange4
);
248 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
249 "blue4", &Blue4
, &Blue4
);
250 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
251 "yellow4", &Yellow4
, &Yellow4
);
252 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
253 "chocolate4", &Chocolate4
, &Chocolate4
);
254 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
255 "purple4", &Purple4
, &Purple4
);
256 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
257 "SteelBlue4", &SteelBlue4
, &SteelBlue4
);
258 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
259 "Plum4", &Plum4
, &Plum4
);
260 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
261 "Maroon4", &Maroon4
, &Maroon4
);
262 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
263 "pink4", &Pink4
, &Pink4
);
264 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
265 "Wheat", &Wheat
, &Wheat
);
266 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
267 "darkslategrey", &DarkSlateGrey
, &DarkSlateGrey
);
270 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
271 "red1", &Red1
, &Red1
);
272 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
273 "green1", &Green1
, &Green1
);
274 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
275 "Orange1", &Orange1
, &Orange1
);
276 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
277 "blue1", &Blue1
, &Blue1
);
278 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
279 "yellow1", &Yellow1
, &Yellow1
);
280 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
281 "chocolate1", &Chocolate1
, &Chocolate1
);
282 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
283 "purple1", &Purple1
, &Purple1
);
284 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
285 "SteelBlue1", &SteelBlue1
, &SteelBlue1
);
286 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
287 "Plum1", &Plum1
, &Plum1
);
288 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
289 "Maroon1", &Maroon1
, &Maroon1
);
290 XAllocNamedColor(display
, DefaultColormap(display
, screen
),
291 "pink1", &Pink1
, &Pink1
);
292 black
= BlackPixel(display
, screen
);
293 white
= WhitePixel(display
, screen
);
295 set_font_path(HEXFONTDIR
);
299 /* This sets up the font path to contain the directories that have the
300 * fonts this program needs.
302 set_font_path(fontdir
)
306 char **font_path
= XGetFontPath(display
, &font_length
);
308 for (i
= 0; (i
< font_length
) && strcmp(font_path
[i
],fontdir
); i
++);
310 if (i
>= font_length
) {
311 char **new_font_path
;
313 if (new_font_path
= (char **) malloc((font_length
+1)*sizeof(char *))) {
314 for(i
= 0; i
< font_length
; i
++)
315 new_font_path
[i
] = font_path
[i
];
316 new_font_path
[i
] = fontdir
;
317 XSetFontPath(display
, new_font_path
, font_length
+ 1);
322 XFreeFontPath(font_path
);
325 /* This sets up the window position, size, fonts, and gcs.
327 set_up_window(width
,height
,size_hints
,argv
,argc
)
329 XSizeHints
*size_hints
;
333 *width
= MAXCOLUMN
*40;
334 *height
= (MAXROW
+4)*20;
335 win
= XCreateSimpleWindow(display
,RootWindow(display
, screen
),0,0,
336 *width
, *height
, 4, white
, black
);
337 size_hints
->flags
= PPosition
| PSize
| PMinSize
;
340 size_hints
->width
= *width
;
341 size_hints
->height
= *height
;
342 size_hints
->min_width
= 300;
343 size_hints
->min_height
= 700;
344 XSetStandardProperties(display
, win
, WINDOWNAME
, ICONNAME
, (int) NULL
, argv
,
346 XSelectInput(display
, win
, ExposureMask
| KeyPressMask
| ButtonPressMask
|
347 StructureNotifyMask
| EnterWindowMask
| LeaveWindowMask
);
348 load_font(&font_info
, FONTNAME
);
349 get_GC(win
, &gc
, font_info
);
350 XSetForeground(display
, gc
, Wheat
.pixel
);
351 XSetBackground(display
, gc
, black
);
352 load_font(&hexfont_info
, HEXFONTNAME
);
353 get_GC(win
, &hexgc
, hexfont_info
);
354 XSetForeground(display
, hexgc
, black
);
355 XSetBackground(display
, hexgc
, DarkSlateGrey
.pixel
);
356 XMapWindow(display
, win
);
362 get_GC(win
, tgc
, tfont_info
)
365 XFontStruct
*tfont_info
;
367 unsigned long valuemask
= 0;
369 unsigned int line_width
= 2;
370 int line_style
= LineSolid
;
371 int cap_style
= CapRound
;
372 int join_style
= JoinRound
;
374 static char dash_list
[] = { 12, 24 };
377 *tgc
= XCreateGC(display
, win
, valuemask
, &values
);
378 XSetFont(display
, *tgc
, tfont_info
->fid
);
379 XSetForeground(display
, *tgc
, white
);
380 XSetLineAttributes(display
, *tgc
, line_width
, line_style
, cap_style
,
382 XSetDashes(display
, *tgc
, dash_offset
, dash_list
, list_length
);
387 load_font(tfont_info
, font_name
)
388 XFontStruct
**tfont_info
;
391 if ((*tfont_info
= XLoadQueryFont(display
, font_name
)) == NULL
) {
392 (void)fprintf(stderr
, "xhextris: Cannot open %s font.\n",font_name
);
397 /* This yells if the window is too small.
401 char *string1
= "Too Small";
402 int y_offset
, x_offset
;
404 y_offset
= font_info
->max_bounds
.ascent
+ 2;
406 XDrawString(display
, win
, gc
, x_offset
, y_offset
, string1
,
410 /* This is required by hextris!
412 * This clears the window.
416 XClearWindow(display
,win
);
419 /* This is required by hextris!
421 * This displays the current score and rows completed.
423 display_scores(score
,rows
)
426 int y_offset
, x_offset
;
429 XSetFillStyle(display
, gc
, FillSolid
);
430 sprintf(scores
,"Score: %6d", *score
);
432 x_offset
= (MAXCOLUMN
+ 1) * 20;
433 XClearArea(display
,win
,x_offset
,y_offset
-20,MAXCOLUMN
*20, 50, False
);
434 XDrawString(display
, win
, gc
, x_offset
, y_offset
, scores
,strlen(scores
));
435 sprintf(scores
,"Rows: %3d", *rows
);
437 XDrawString(display
, win
, gc
, x_offset
, y_offset
, scores
,strlen(scores
));
441 /* This is required by hextris!
443 * This displays the help information.
447 int y_offset
, x_offset
, i
;
448 static char *message
[] = { "The keys to press are:",
449 "J,j,4 - move left.",
450 "L,l,6 - move right.",
451 "K,k,5 - rotate ccw.",
452 "I,i,8 - rotate cw.",
456 "U,u - unpause game.",
457 "R,r - redisplay game.",
458 "H,h - show high scores.",
462 "--------------------",
469 XSetFillStyle(display
, gc
, FillSolid
);
471 x_offset
= (MAXCOLUMN
+ 1) * 20;
472 for (i
= 0; i
< 19; i
++)
473 XDrawString(display
, win
, gc
, x_offset
, y_offset
+(i
*17), message
[i
],
480 int y_offset
, x_offset
, i
;
481 static char *message
[] = { "Keys:",
486 XSetFillStyle(display
, gc
, FillSolid
);
488 x_offset
= (MAXCOLUMN
+ 1) * 26;
489 for (i
= 0; i
< 4; i
++)
490 XDrawString(display
, win
, gc
, x_offset
, y_offset
+(i
*17), message
[i
],
495 /* This is required by hextris!
497 * This displays the high score list.
499 display_high_scores(high_scores
)
500 high_score_t high_scores
[MAXHIGHSCORES
];
503 static int x_offset
[5] = {5,30,150,200,300};
504 static char *header
[] = {"#","Name","UID","Score","Rows"};
505 char message
[40] = "";
507 XClearWindow(display
,win
);
508 XSetFillStyle(display
, gc
, FillSolid
);
510 for (i
= 0; i
< 5; i
++)
511 XDrawString(display
, win
, gc
, x_offset
[i
], y_offset
,
512 header
[i
],strlen(header
[i
]));
514 for (i
= 0; i
< ((MAXHIGHSCORES
> 40) ? 30 : MAXHIGHSCORES
); i
++) {
516 XDrawString(display
, win
, gc
, x_offset
[0], y_offset
+(i
*17),
517 message
,strlen(message
));
518 XDrawString(display
, win
, gc
, x_offset
[1], y_offset
+(i
*17),
519 high_scores
[i
].name
,strlen(high_scores
[i
].name
));
520 strncpy(message
, high_scores
[i
].userid
, 5);
521 XDrawString(display
, win
, gc
, x_offset
[2], y_offset
+(i
*17),
522 message
, strlen(message
));
523 itoa(high_scores
[i
].score
,message
);
524 XDrawString(display
, win
, gc
, x_offset
[3], y_offset
+(i
*17),
525 message
,strlen(message
));
526 itoa(high_scores
[i
].rows
,message
);
527 XDrawString(display
, win
, gc
, x_offset
[4], y_offset
+(i
*17),
528 message
,strlen(message
));
533 /* This is required by hextris!
535 * This displays the next piece to be dropped.
537 show_next_piece(npiece
)
542 tpiece
.type
= npiece
->type
;
543 tpiece
.rotation
= npiece
->rotation
;
545 tpiece
.column
= MAXCOLUMN
+6;
546 XClearArea(display
,win
,(MAXCOLUMN
+3)*18,0,150,140, False
);
547 init_piece(&tpiece
, 0);
551 /* This is required by hextris!
553 * This draws one hex at the specified row and column specified.
555 draw_hex(row
,column
,fill
,type
)
556 int row
,column
,fill
,type
;
558 int y_offset
, x_offset
;
561 x_offset
= 20 + column
* 16;
562 y_offset
= 20 + row
* 19 + (column
& 1) * 9;
567 XSetForeground(display
, hexgc
, Orange1
.pixel
);
568 XSetBackground(display
, hexgc
, Orange4
.pixel
);
571 XSetForeground(display
, hexgc
, Red1
.pixel
);
572 XSetBackground(display
, hexgc
, Red4
.pixel
);
575 XSetForeground(display
, hexgc
, Blue1
.pixel
);
576 XSetBackground(display
, hexgc
, Blue4
.pixel
);
579 XSetForeground(display
, hexgc
, Green1
.pixel
);
580 XSetBackground(display
, hexgc
, Green4
.pixel
);
583 XSetForeground(display
, hexgc
, Yellow1
.pixel
);
584 XSetBackground(display
, hexgc
, Yellow4
.pixel
);
587 XSetForeground(display
, hexgc
, Chocolate1
.pixel
);
588 XSetBackground(display
, hexgc
, Chocolate4
.pixel
);
591 XSetForeground(display
, hexgc
, Purple1
.pixel
);
592 XSetBackground(display
, hexgc
, Purple4
.pixel
);
595 XSetForeground(display
, hexgc
, SteelBlue1
.pixel
);
596 XSetBackground(display
, hexgc
, SteelBlue4
.pixel
);
599 XSetForeground(display
, hexgc
, Plum1
.pixel
);
600 XSetBackground(display
, hexgc
, Plum4
.pixel
);
603 XSetForeground(display
, hexgc
, Maroon1
.pixel
);
604 XSetBackground(display
, hexgc
, Maroon4
.pixel
);
607 XSetForeground(display
, hexgc
, Pink1
.pixel
);
608 XSetBackground(display
, hexgc
, Pink4
.pixel
);
612 XSetForeground(display
,hexgc
,DarkSlateGrey
.pixel
);
613 XSetBackground(display
, hexgc
, DarkSlateGrey
.pixel
);
616 XDrawString(display
, win
, hexgc
, x_offset
, y_offset
, hex
, strlen(hex
));
620 draw_pos(column
,fill
,type
)
621 int column
,fill
,type
;
623 int y_offset
, x_offset
;
626 x_offset
= 20 + column
* 16;
627 y_offset
= 20 + (MAXROW
+ 2) * 19 + (column
& 1) * 9;
632 XSetForeground(display
, hexgc
, Orange1
.pixel
);
633 XSetBackground(display
, hexgc
, Orange4
.pixel
);
636 XSetForeground(display
, hexgc
, Red1
.pixel
);
637 XSetBackground(display
, hexgc
, Red4
.pixel
);
640 XSetForeground(display
, hexgc
, Blue1
.pixel
);
641 XSetBackground(display
, hexgc
, Blue4
.pixel
);
644 XSetForeground(display
, hexgc
, Green1
.pixel
);
645 XSetBackground(display
, hexgc
, Green4
.pixel
);
648 XSetForeground(display
, hexgc
, Yellow1
.pixel
);
649 XSetBackground(display
, hexgc
, Yellow4
.pixel
);
652 XSetForeground(display
, hexgc
, Chocolate1
.pixel
);
653 XSetBackground(display
, hexgc
, Chocolate4
.pixel
);
656 XSetForeground(display
, hexgc
, Purple1
.pixel
);
657 XSetBackground(display
, hexgc
, Purple4
.pixel
);
660 XSetForeground(display
, hexgc
, SteelBlue1
.pixel
);
661 XSetBackground(display
, hexgc
, SteelBlue4
.pixel
);
664 XSetForeground(display
, hexgc
, Plum1
.pixel
);
665 XSetBackground(display
, hexgc
, Plum4
.pixel
);
668 XSetForeground(display
, hexgc
, Maroon1
.pixel
);
669 XSetBackground(display
, hexgc
, Maroon4
.pixel
);
672 XSetForeground(display
, hexgc
, Pink1
.pixel
);
673 XSetBackground(display
, hexgc
, Pink4
.pixel
);
677 XSetForeground(display
,hexgc
,DarkSlateGrey
.pixel
);
678 XSetBackground(display
, hexgc
, DarkSlateGrey
.pixel
);
681 XDrawString(display
, win
, hexgc
, x_offset
, y_offset
, hex
, strlen(hex
));
685 /* This is required by hextris!
687 * This ends the game by closing everything down and exiting.
691 XFreeGC (display
, gc
);
692 XFreeGC (display
, hexgc
);
693 XDestroyWindow (display
, win
);
694 XCloseDisplay (display
);