1 /* SCCS Id: @(#)winami.c 3.2 2000/01/12 */
2 /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993,1996. */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 #include "NH:sys/amiga/windefs.h"
6 #include "NH:sys/amiga/winext.h"
7 #include "NH:sys/amiga/winproto.h"
8 #include "dlb.h"
9
10 #ifdef AMIGA_INTUITION
11
12 static int FDECL( put_ext_cmd, ( char *, int, struct amii_WinDesc *, int ) );
13
14 struct amii_DisplayDesc *amiIDisplay; /* the Amiga Intuition descriptor */
15 struct Rectangle lastinvent, lastmsg;
16 int clipping = 0;
17 int clipx=0;
18 int clipy=0;
19 int clipxmax=0;
20 int clipymax=0;
21 int scrollmsg = 1;
22 int alwaysinvent = 0;
23 int amii_numcolors;
24 long amii_scrnmode;
25
26 /* Interface definition, for use by windows.c and winprocs.h to provide
27 * the intuition interface for the amiga...
28 */
29 struct window_procs amii_procs =
30 {
31 "amii",
32 amii_init_nhwindows,
33 amii_player_selection,
34 amii_askname,
35 amii_get_nh_event,
36 amii_exit_nhwindows,
37 amii_suspend_nhwindows,
38 amii_resume_nhwindows,
39 amii_create_nhwindow,
40 amii_clear_nhwindow,
41 amii_display_nhwindow,
42 amii_destroy_nhwindow,
43 amii_curs,
44 amii_putstr,
45 amii_display_file,
46 amii_start_menu,
47 amii_add_menu,
48 amii_end_menu,
49 amii_select_menu,
50 genl_message_menu,
51 amii_update_inventory,
52 amii_mark_synch,
53 amii_wait_synch,
54 #ifdef CLIPPING
55 amii_cliparound,
56 #endif
57 #ifdef POSITIONBAR
58 donull,
59 #endif
60 amii_print_glyph,
61 amii_raw_print,
62 amii_raw_print_bold,
63 amii_nhgetch,
64 amii_nh_poskey,
65 amii_bell,
66 amii_doprev_message,
67 amii_yn_function,
68 amii_getlin,
69 amii_get_ext_cmd,
70 amii_number_pad,
71 amii_delay_output,
72 #ifdef CHANGE_COLOR /* only a Mac option currently */
73 amii_change_color,
74 amii_get_color_string,
75 #endif
76 /* other defs that really should go away (they're tty specific) */
77 amii_delay_output,
78 amii_delay_output,
79 amii_outrip
80 };
81
82 /* The view window layout uses the same function names so we can use
83 * a shared library to allow the executable to be smaller.
84 */
85 struct window_procs amiv_procs =
86 {
87 "amitile",
88 amii_init_nhwindows,
89 amii_player_selection,
90 amii_askname,
91 amii_get_nh_event,
92 amii_exit_nhwindows,
93 amii_suspend_nhwindows,
94 amii_resume_nhwindows,
95 amii_create_nhwindow,
96 amii_clear_nhwindow,
97 amii_display_nhwindow,
98 amii_destroy_nhwindow,
99 amii_curs,
100 amii_putstr,
101 amii_display_file,
102 amii_start_menu,
103 amii_add_menu,
104 amii_end_menu,
105 amii_select_menu,
106 genl_message_menu,
107 amii_update_inventory,
108 amii_mark_synch,
109 amii_wait_synch,
110 #ifdef CLIPPING
111 amii_cliparound,
112 #endif
113 #ifdef POSITIONBAR
114 donull,
115 #endif
116 amii_print_glyph,
117 amii_raw_print,
118 amii_raw_print_bold,
119 amii_nhgetch,
120 amii_nh_poskey,
121 amii_bell,
122 amii_doprev_message,
123 amii_yn_function,
124 amii_getlin,
125 amii_get_ext_cmd,
126 amii_number_pad,
127 amii_delay_output,
128 #ifdef CHANGE_COLOR /* only a Mac option currently */
129 amii_change_color,
130 amii_get_color_string,
131 #endif
132 /* other defs that really should go away (they're tty specific) */
133 amii_delay_output,
134 amii_delay_output,
135 amii_outrip
136 };
137
138 unsigned short amii_initmap[ AMII_MAXCOLORS ];
139 /* Default pens used unless use overides in nethack.cnf. */
140 unsigned short amii_init_map[ AMII_MAXCOLORS ] =
141 {
142 0x0000, /* color #0 C_BLACK */
143 0x0FFF, /* color #1 C_WHITE */
144 0x0830, /* color #2 C_BROWN */
145 0x07ac, /* color #3 C_CYAN */
146 0x0181, /* color #4 C_GREEN */
147 0x0C06, /* color #5 C_MAGENTA */
148 0x023E, /* color #6 C_BLUE */
149 0x0c00, /* color #7 C_RED */
150 };
151
152 unsigned short amiv_init_map[ AMII_MAXCOLORS ] =
153 {
154 0x0000, /* color #0 C_BLACK */
155 0x0fff, /* color #1 C_WHITE */
156 0x00bf, /* color #2 C_CYAN */
157 0x0f60, /* color #3 C_ORANGE */
158 0x000f, /* color #4 C_BLUE */
159 0x0090, /* color #5 C_GREEN */
160 0x069b, /* color #6 C_GREY */
161 0x0f00, /* color #7 C_RED */
162 0x06f0, /* color #8 C_LTGREEN */
163 0x0ff0, /* color #9 C_YELLOW */
164 0x0f0f, /* color #10 C_MAGENTA */
165 0x0940, /* color #11 C_BROWN */
166 0x0466, /* color #12 C_GREYBLUE */
167 0x0c40, /* color #13 C_LTBROWN */
168 0x0ddb, /* color #14 C_LTGREY */
169 0x0fb9, /* color #15 C_PEACH */
170
171 /* Pens for dripens etc under AA or better */
172 0x0222, /* color #16 */
173 0x0fdc, /* color #17 */
174 0x0000, /* color #18 */
175 0x0ccc, /* color #19 */
176 0x0bbb, /* color #20 */
177 0x0BA9, /* color #21 */
178 0x0999, /* color #22 */
179 0x0987, /* color #23 */
180 0x0765, /* color #24 */
181 0x0666, /* color #25 */
182 0x0555, /* color #26 */
183 0x0533, /* color #27 */
184 0x0333, /* color #28 */
185 0x018f, /* color #29 */
186 0x0f81, /* color #30 */
187 0x0fff, /* color #31 */
188 };
189
190 #if !defined( TTY_GRAPHICS ) || defined( SHAREDLIB ) /* this should be shared better */
191 char morc; /* the character typed in response to a --more-- prompt */
192 #endif
193 char spaces[ 76 ] =
194 " ";
195
196 winid WIN_BASE = WIN_ERR;
197 winid WIN_OVER = WIN_ERR;
198 winid amii_rawprwin = WIN_ERR;
199
200 /* Changed later during window/screen opens... */
201 int txwidth = FONTWIDTH, txheight = FONTHEIGHT, txbaseline = FONTBASELINE;
202
203 /* If a 240 or more row screen is in front when we start, this will be
204 * set to 1, and the windows will be given borders to allow them to be
205 * arranged differently. The Message window may eventually get a scroller...
206 */
207 int bigscreen = 0;
208
209 /* This gadget data is replicated for menu/text windows... */
210 struct PropInfo PropScroll = { AUTOKNOB|FREEVERT,
211 0xffff,0xffff, 0xffff,0xffff, };
212 struct Image Image1 = { 0,0, 7,102, 0, NULL, 0x0000,0x0000, NULL };
213 struct Gadget MenuScroll = {
214 NULL, -15,10, 15,-19, GRELRIGHT|GRELHEIGHT,
215 RELVERIFY|FOLLOWMOUSE|RIGHTBORDER|GADGIMMEDIATE|RELVERIFY,
216 PROPGADGET, (APTR)&Image1, NULL, NULL, NULL, (APTR)&PropScroll,
217 1, NULL
218 };
219
220 /* This gadget is for the message window... */
221 struct PropInfo MsgPropScroll = { AUTOKNOB|FREEVERT,
222 0xffff,0xffff, 0xffff,0xffff, };
223 struct Image MsgImage1 = { 0,0, 7,102, 0, NULL, 0x0000,0x0000, NULL };
224 struct Gadget MsgScroll = {
225 NULL, -15,10, 14,-19, GRELRIGHT|GRELHEIGHT,
226 RELVERIFY|FOLLOWMOUSE|RIGHTBORDER|GADGIMMEDIATE|RELVERIFY,
227 PROPGADGET, (APTR)&MsgImage1, NULL, NULL, NULL, (APTR)&MsgPropScroll,
228 1, NULL
229 };
230
231 int wincnt=0; /* # of nh windows opened */
232
233 /* We advertise a public screen to allow some people to do other things
234 * while they are playing... like compiling...
235 */
236
237 #ifdef INTUI_NEW_LOOK
238 struct TagItem tags[] =
239 {
240 { WA_PubScreenName, (ULONG)"NetHack" },
241 { TAG_DONE, 0 },
242 };
243 #endif
244
245 /*
246 * The default dimensions and status values for each window type. The
247 * data here is generally changed in create_nhwindow(), so beware that
248 * what you see here may not be exactly what you get.
249 */
250 struct win_setup new_wins[] =
251 {
252
253 /* First entry not used, types are based at 1 */
254 {{0}},
255
256 /* NHW_MESSAGE */
257 {{0,1,640,11,
258 0xff,0xff,
259 NEWSIZE|GADGETUP|GADGETDOWN|MOUSEMOVE|MOUSEBUTTONS|RAWKEY,
260 BORDERLESS|ACTIVATE|SMART_REFRESH
261 #ifdef INTUI_NEW_LOOK
262 |WFLG_NW_EXTENDED
263 #endif
264 ,
265 NULL,NULL,(UBYTE*)"Messages",NULL,NULL,320,40,0xffff,0xffff,CUSTOMSCREEN,
266 #ifdef INTUI_NEW_LOOK
267 tags
268 #endif
269 },
270 0,0,1,1,80,80},
271
272 /* NHW_STATUS */
273 {{0,181,640,24,
274 0xff,0xff,
275 RAWKEY|MENUPICK|DISKINSERTED,
276 BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP
277 #ifdef INTUI_NEW_LOOK
278 |WFLG_NW_EXTENDED
279 #endif
280 ,
281 NULL,NULL,(UBYTE*)"Game Status",NULL,NULL,0,0,0xffff,0xffff,CUSTOMSCREEN,
282 #ifdef INTUI_NEW_LOOK
283 tags
284 #endif
285 },
286 0,0,2,2,78,78},
287
288 /* NHW_MAP */
289 {{0,0,WIDTH,WINDOWHEIGHT,
290 0xff,0xff,
291 RAWKEY|MENUPICK|MOUSEBUTTONS|ACTIVEWINDOW|MOUSEMOVE,
292 BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP
293 #ifdef INTUI_NEW_LOOK
294 |WFLG_NW_EXTENDED
295 #endif
296 ,
297 NULL,NULL,(UBYTE*)"Dungeon Map",NULL,NULL,64,64,0xffff,0xffff,CUSTOMSCREEN,
298 #ifdef INTUI_NEW_LOOK
299 tags
300 #endif
301 },
302 0,0,22,22,80,80},
303
304 /* NHW_MENU */
305 {{400,10,10,10,
306 0xff,0xff,
307 RAWKEY|MENUPICK|DISKINSERTED|MOUSEMOVE|MOUSEBUTTONS|
308 GADGETUP|GADGETDOWN|CLOSEWINDOW|VANILLAKEY|NEWSIZE|INACTIVEWINDOW,
309 WINDOWSIZING|WINDOWCLOSE|WINDOWDRAG|ACTIVATE|SMART_REFRESH
310 #ifdef INTUI_NEW_LOOK
311 |WFLG_NW_EXTENDED
312 #endif
313 ,
314 &MenuScroll,NULL,NULL,NULL,NULL,64,32,0xffff,0xffff,CUSTOMSCREEN,
315 #ifdef INTUI_NEW_LOOK
316 tags
317 #endif
318 },
319 0,0,1,1,22,78},
320
321 /* NHW_TEXT */
322 {{0,0,640,200,
323 0xff,0xff,
324 RAWKEY|MENUPICK|DISKINSERTED|MOUSEMOVE|
325 GADGETUP|CLOSEWINDOW|VANILLAKEY|NEWSIZE,
326 WINDOWSIZING|WINDOWCLOSE|WINDOWDRAG|ACTIVATE|SMART_REFRESH
327 #ifdef INTUI_NEW_LOOK
328 |WFLG_NW_EXTENDED
329 #endif
330 ,
331 &MenuScroll,NULL,(UBYTE*)NULL,NULL,NULL,100,32,0xffff,0xffff,CUSTOMSCREEN,
332 #ifdef INTUI_NEW_LOOK
333 tags
334 #endif
335 },
336 0,0,1,1,22,78},
337
338 /* NHW_BASE */
339 {{0,0,WIDTH,WINDOWHEIGHT,
340 0xff,0xff,
341 RAWKEY|MENUPICK|MOUSEBUTTONS,
342 BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP
343 #ifdef INTUI_NEW_LOOK
344 |WFLG_NW_EXTENDED
345 #endif
346 ,
347 NULL,NULL,(UBYTE*)NULL,NULL,NULL,-1,-1,0xffff,0xffff,CUSTOMSCREEN,
348 #ifdef INTUI_NEW_LOOK
349 tags
350 #endif
351 },
352 0,0,22,22,80,80},
353
354 /* NHW_OVER */
355 {{320,20,319,179,
356 0xff,0xff,
357 RAWKEY|MENUPICK|MOUSEBUTTONS,
358 BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP
359 #ifdef INTUI_NEW_LOOK
360 |WFLG_NW_EXTENDED
361 #endif
362 ,
363 NULL,NULL,(UBYTE*)NULL,NULL,NULL,64,32,0xffff,0xffff,CUSTOMSCREEN,
364 #ifdef INTUI_NEW_LOOK
365 tags
366 #endif
367 },
368 0,0,22,22,80,80},
369 };
370
371 const char winpanicstr[] = "Bad winid %d in %s()";
372
373 /* The opened windows information */
374 struct amii_WinDesc *amii_wins[ MAXWIN + 1 ];
375
376 #ifdef INTUI_NEW_LOOK
377 /*
378 * NUMDRIPENS varies based on headers, so don't use it
379 * here, its value is used elsewhere.
380 */
381 UWORD amii_defpens[ 20 ];
382
383 struct TagItem scrntags[] =
384 {
385 { SA_PubName, (ULONG)"NetHack" },
386 { SA_Overscan, OSCAN_TEXT },
387 { SA_AutoScroll, TRUE },
388 #if LIBRARY_VERSION >= 39
389 { SA_Interleaved, TRUE },
390 #endif
391 { SA_Pens, (ULONG)0 },
392 { SA_DisplayID, 0 },
393 { TAG_DONE, 0 },
394 };
395
396 #endif
397
398 struct NewScreen NewHackScreen =
399 {
400 0, 0, WIDTH, SCREENHEIGHT, 3,
401 0, 1, /* DetailPen, BlockPen */
402 HIRES,
403 CUSTOMSCREEN
404 #ifdef INTUI_NEW_LOOK
405 |NS_EXTENDED
406 #endif
407 ,
408 &Hack80, /* Font */
409 NULL, /*(UBYTE *)" NetHack X.Y.Z" */
410 NULL, /* Gadgets */
411 NULL, /* CustomBitmap */
412 #ifdef INTUI_NEW_LOOK
413 scrntags
414 #endif
415 };
416
417 /*
418 * plname is filled either by an option (-u Player or -uPlayer) or
419 * explicitly (by being the wizard) or by askname.
420 * It may still contain a suffix denoting pl_character.
421 * Always called after init_nhwindows() and before display_gamewindows().
422 */
423 void
amii_askname()424 amii_askname()
425 {
426 *plname = 0;
427 do {
428 amii_getlin( "Who are you?", plname );
429 } while( strlen( plname ) == 0 );
430
431 if( *plname == '\33' )
432 {
433 clearlocks();
434 exit_nhwindows(NULL);
435 terminate(0);
436 }
437 }
438
439 /* Discarded ... -jhsa
440 #include "NH:sys/amiga/char.c"
441 */
442
443 /* Get the player selection character */
444
445 #if 0 /* New function at the bottom */
446 void
amii_player_selection()447 amii_player_selection()
448 {
449 register struct Window *cwin;
450 register struct IntuiMessage *imsg;
451 register int aredone = 0;
452 register struct Gadget *gd;
453 static int once = 0;
454 long class, code;
455
456 amii_clear_nhwindow( WIN_BASE );
457 if (validrole(flags.initrole))
458 return;
459 else {
460 flags.initrole=randrole();
461 return;
462 }
463 #if 0 /* Don't query the user ... instead give random character -jhsa */
464
465 #if 0 /* OBSOLETE */
466 if( *pl_character ){
467 pl_character[ 0 ] = toupper( pl_character[ 0 ] );
468 if( index( pl_classes, pl_character[ 0 ] ) )
469 return;
470 }
471 #endif
472
473 if( !once ){
474 if( bigscreen ){
475 Type_NewWindowStructure1.TopEdge =
476 (HackScreen->Height/2) - (Type_NewWindowStructure1.Height/2);
477 }
478 for( gd = Type_NewWindowStructure1.FirstGadget; gd;
479 gd = gd->NextGadget )
480 {
481 if( gd->GadgetID != 0 )
482 SetBorder( gd );
483 }
484 once = 1;
485 }
486
487 if( WINVERS_AMIV )
488 {
489 # ifdef INTUI_NEW_LOOK
490 Type_NewWindowStructure1.Extension = wintags;
491 Type_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED;
492 fillhook.h_Entry = (ULONG(*)())LayerFillHook;
493 fillhook.h_Data = (void *)-2;
494 fillhook.h_SubEntry = 0;
495 #endif
496 }
497
498 Type_NewWindowStructure1.Screen = HackScreen;
499 if( ( cwin = OpenShWindow( (void *)&Type_NewWindowStructure1 ) ) == NULL )
500 {
501 return;
502 }
503 #if 0
504 WindowToFront( cwin );
505 #endif
506
507 while( !aredone )
508 {
509 WaitPort( cwin->UserPort );
510 while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL )
511 {
512 class = imsg->Class;
513 code = imsg->Code;
514 gd = (struct Gadget *)imsg->IAddress;
515 ReplyMsg( (struct Message *)imsg );
516
517 switch( class )
518 {
519 case VANILLAKEY:
520 if( index( pl_classes, toupper( code ) ) )
521 {
522 pl_character[0] = toupper( code );
523 aredone = 1;
524 }
525 else if( code == ' ' || code == '\n' || code == '\r' )
526 {
527 flags.initrole = randrole();
528 #if 0 /* OBSOLETE */
529 #ifdef TOURIST
530 strcpy( pl_character, roles[ rnd( 11 ) ] );
531 #else
532 strcpy( pl_character, roles[ rnd( 10 ) ] );
533 #endif
534 #endif
535 aredone = 1;
536 amii_clear_nhwindow( WIN_BASE );
537 CloseShWindow( cwin );
538 RandomWindow( pl_character );
539 return;
540 }
541 else if( code == 'q' || code == 'Q' )
542 {
543 CloseShWindow( cwin );
544 clearlocks();
545 exit_nhwindows(NULL);
546 terminate(0);
547 }
548 else
549 DisplayBeep( NULL );
550 break;
551
552 case GADGETUP:
553 switch( gd->GadgetID )
554 {
555 case 1: /* Random Character */
556 flags.initrole = randrole();
557 #if 0 /* OBSOLETE */
558 #ifdef TOURIST
559 strcpy( pl_character, roles[ rnd( 11 ) ] );
560 #else
561 strcpy( pl_character, roles[ rnd( 10 ) ] );
562 #endif
563 #endif
564 amii_clear_nhwindow( WIN_BASE );
565 CloseShWindow( cwin );
566 RandomWindow( pl_character );
567 return;
568
569 default:
570 pl_character[0] = gd->GadgetID;
571 break;
572 }
573 aredone = 1;
574 break;
575
576 case CLOSEWINDOW:
577 CloseShWindow( cwin );
578 clearlocks();
579 exit_nhwindows(NULL);
580 terminate(0);
581 break;
582 }
583 }
584 }
585 amii_clear_nhwindow( WIN_BASE );
586 CloseShWindow( cwin );
587 #endif /* Do not query user ... -jhsa */
588 }
589 #endif /* Function elsewhere */
590
591 #if 0 /* Unused ... -jhsa */
592
593 #include "NH:sys/amiga/randwin.c"
594
595 void
RandomWindow(name)596 RandomWindow( name )
597 char *name;
598 {
599 struct MsgPort *tport;
600 struct timerequest *trq;
601 static int once = 0;
602 struct Gadget *gd;
603 struct Window *w;
604 struct IntuiMessage *imsg;
605 int ticks = 0, aredone = 0, timerdone = 0;
606 long mask, got;
607
608 tport = CreatePort( 0, 0 );
609 trq = (struct timerequest *)CreateExtIO( tport, sizeof( *trq ) );
610 if( tport == NULL || trq == NULL )
611 {
612 allocerr:
613 if( tport ) DeletePort( tport );
614 if( trq ) DeleteExtIO( (struct IORequest *)trq );
615 Delay( 8 * 50 );
616 return;
617 }
618
619 if( OpenDevice( TIMERNAME, UNIT_VBLANK, (struct IORequest *)trq, 0L ) != 0 )
620 goto allocerr;
621
622 trq->tr_node.io_Command = TR_ADDREQUEST;
623 trq->tr_time.tv_secs = 8;
624 trq->tr_time.tv_micro = 0;
625
626 SendIO( (struct IORequest *)trq );
627
628 /* Place the name in the center of the screen */
629 Rnd_IText5.IText = name;
630 Rnd_IText6.LeftEdge = Rnd_IText4.LeftEdge +
631 (strlen(Rnd_IText4.IText)+1)*8;
632 Rnd_NewWindowStructure1.Width = (
633 (strlen( Rnd_IText2.IText )+1) * 8 ) +
634 HackScreen->WBorLeft + HackScreen->WBorRight;
635 Rnd_IText5.LeftEdge = (Rnd_NewWindowStructure1.Width -
636 (strlen(name)*8))/2;
637
638 gd = Rnd_NewWindowStructure1.FirstGadget;
639 gd->LeftEdge = (Rnd_NewWindowStructure1.Width - gd->Width)/2;
640 /* Chose correct modifier */
641 Rnd_IText6.IText = "a";
642 switch( *name )
643 {
644 case 'a': case 'e': case 'i': case 'o':
645 case 'u': case 'A': case 'E': case 'I':
646 case 'O': case 'U':
647 Rnd_IText6.IText = "an";
648 break;
649 }
650
651 if( !once )
652 {
653 if( bigscreen )
654 {
655 Rnd_NewWindowStructure1.TopEdge =
656 (HackScreen->Height/2) - (Rnd_NewWindowStructure1.Height/2);
657 }
658 for( gd = Rnd_NewWindowStructure1.FirstGadget; gd; gd = gd->NextGadget )
659 {
660 if( gd->GadgetID != 0 )
661 SetBorder( gd );
662 }
663 Rnd_NewWindowStructure1.IDCMPFlags |= VANILLAKEY;
664
665 once = 1;
666 }
667
668 if( WINVERS_AMIV )
669 {
670 #ifdef INTUI_NEW_LOOK
671 Rnd_NewWindowStructure1.Extension = wintags;
672 Rnd_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED;
673 fillhook.h_Entry = (ULONG(*)())LayerFillHook;
674 fillhook.h_Data = (void *)-2;
675 fillhook.h_SubEntry = 0;
676 #endif
677 }
678
679 Rnd_NewWindowStructure1.Screen = HackScreen;
680 if( ( w = OpenShWindow( (void *)&Rnd_NewWindowStructure1 ) ) == NULL )
681 {
682 AbortIO( (struct IORequest *)trq );
683 WaitIO( (struct IORequest *)trq );
684 CloseDevice( (struct IORequest *)trq );
685 DeleteExtIO( (struct IORequest *) trq );
686 DeletePort( tport );
687 Delay( 50 * 8 );
688 return;
689 }
690
691 PrintIText( w->RPort, &Rnd_IntuiTextList1, 0, 0 );
692
693 mask = (1L << tport->mp_SigBit)|(1L << w->UserPort->mp_SigBit);
694 while( !aredone )
695 {
696 got = Wait( mask );
697 if( got & (1L << tport->mp_SigBit ) )
698 {
699 aredone = 1;
700 timerdone = 1;
701 GetMsg( tport );
702 }
703 while( w && ( imsg = (struct IntuiMessage *) GetMsg( w->UserPort ) ) )
704 {
705 switch( (long)imsg->Class )
706 {
707 /* Must be up for a little while... */
708 case INACTIVEWINDOW:
709 if( ticks >= 40 )
710 aredone = 1;
711 break;
712
713 case INTUITICKS:
714 ++ticks;
715 break;
716
717 case GADGETUP:
718 aredone = 1;
719 break;
720
721 case VANILLAKEY:
722 if(imsg->Code=='\n' || imsg->Code==' ' || imsg->Code=='\r')
723 aredone = 1;
724 break;
725 }
726 ReplyMsg( (struct Message *)imsg );
727 }
728 }
729
730 if( !timerdone )
731 {
732 AbortIO( (struct IORequest *)trq );
733 WaitIO( (struct IORequest *)trq );
734 }
735
736 CloseDevice( (struct IORequest *)trq );
737 DeleteExtIO( (struct IORequest *) trq );
738 DeletePort( tport );
739 if(w) CloseShWindow( w );
740 }
741 #endif /* Discarded randwin ... -jhsa */
742
743 /* this should probably not be needed (or be renamed)
744 void
745 flush_output(){} */
746
747 /* Read in an extended command - doing command line completion for
748 * when enough characters have been entered to make a unique command.
749 */
750 int
amii_get_ext_cmd(void)751 amii_get_ext_cmd( void )
752 {
753 menu_item *mip;
754 anything id;
755 struct amii_WinDesc *cw;
756 #ifdef EXTMENU
757 winid win;
758 int i;
759 char buf[256];
760 #endif
761 int colx;
762 int bottom = 0;
763 struct Window *w;
764 char obufp[ 100 ];
765 register char *bufp = obufp;
766 register int c;
767 int com_index, oindex;
768 int did_comp=0; /* did successful completion? */
769 int sel = -1;
770
771 if( WIN_MESSAGE == WIN_ERR || ( cw = amii_wins[ WIN_MESSAGE ] ) == NULL )
772 panic(winpanicstr, WIN_MESSAGE, "get_ext_cmd");
773 w = cw->win;
774 bottom = amii_msgborder( w );
775 colx = 3;
776
777 #ifdef EXTMENU
778 if (iflags.extmenu) {
779 win = amii_create_nhwindow( NHW_MENU );
780 amii_start_menu( win );
781 pline("#");
782 amii_putstr( WIN_MESSAGE, -1, " " );
783
784 for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i )
785 {
786 id.a_char = *extcmdlist[ i ].ef_txt;
787 sprintf( buf, "%-10s - %s ",
788 extcmdlist[ i ].ef_txt,
789 extcmdlist[ i ].ef_desc );
790 amii_add_menu( win, NO_GLYPH, &id, extcmdlist[i].ef_txt[0], 0, 0, buf, MENU_UNSELECTED);
791 }
792
793 amii_end_menu( win, (char*)0 );
794 sel = amii_select_menu( win, PICK_ONE, &mip );
795 amii_destroy_nhwindow( win );
796
797 if( sel == 1 )
798 {
799 sel = mip->item.a_char;
800 for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i )
801 {
802 if( sel == extcmdlist[i].ef_txt[0] )
803 break;
804 }
805
806 /* copy in the text */
807 if( extcmdlist[ i ].ef_txt != NULL )
808 {
809 amii_clear_nhwindow( WIN_MESSAGE );
810 (void) put_ext_cmd( (char *)extcmdlist[i].ef_txt, 0, cw, bottom );
811 return( i );
812 }
813 else
814 DisplayBeep( NULL );
815 }
816
817 return( -1 );
818 } else {
819 #else
820
821 amii_clear_nhwindow( WIN_MESSAGE ); /* Was NHW_MESSAGE */
822 if( scrollmsg )
823 {
824 pline("#");
825 amii_addtopl(" ");
826 }
827 else
828 {
829 pline("# ");
830 }
831
832 sel = -1;
833 while((c = WindowGetchar()) != EOF)
834 {
835 amii_curs( WIN_MESSAGE, colx, bottom );
836 if(c == '?' )
837 {
838 int win, i;
839 char buf[ 100 ];
840
841 if(did_comp){
842 while(bufp!=obufp)
843 {
844 bufp--;
845 amii_curs(WIN_MESSAGE, --colx, bottom);
846 Text(w->RPort,spaces,1);
847 amii_curs(WIN_MESSAGE,colx,bottom);
848 did_comp=0;
849 }
850 }
851
852 win = amii_create_nhwindow( NHW_MENU );
853 amii_start_menu( win );
854
855 for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i )
856 {
857 id.a_char = extcmdlist[i].ef_txt[0];
858 sprintf( buf, "%-10s - %s ",
859 extcmdlist[ i ].ef_txt,
860 extcmdlist[ i ].ef_desc );
861 amii_add_menu( win, NO_GLYPH, &id, extcmdlist[i].ef_txt[0], 0,
862 0, buf, MENU_UNSELECTED);
863 }
864
865 amii_end_menu( win, (char*)0 );
866 sel = amii_select_menu( win, PICK_ONE, &mip );
867 amii_destroy_nhwindow( win );
868
869 if( sel == 0 )
870 {
871 return( -1 );
872 }
873 else
874 {
875 sel = mip->item.a_char;
876 for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i )
877 {
878 if( sel == extcmdlist[i].ef_txt[0] )
879 break;
880 }
881
882 /* copy in the text */
883 if( extcmdlist[ i ].ef_txt != NULL )
884 {
885 amii_clear_nhwindow( WIN_MESSAGE );
886 strcpy( bufp = obufp, extcmdlist[ i ].ef_txt );
887 (void) put_ext_cmd( obufp, colx, cw, bottom );
888 return( i );
889 }
890 else
891 DisplayBeep( NULL );
892 }
893 }
894 else if(c == '\033')
895 {
896 return( -1 );
897 }
898 else if(c == '\b')
899 {
900 if(did_comp){
901 while(bufp!=obufp){
902 bufp--;
903 amii_curs(WIN_MESSAGE, --colx, bottom);
904 Text(w->RPort,spaces,1);
905 amii_curs(WIN_MESSAGE,colx,bottom);
906 did_comp=0;
907 sel = -1;
908 }
909 }
910 else if(bufp != obufp)
911 {
912 sel = -1;
913 bufp--;
914 amii_curs( WIN_MESSAGE, --colx, bottom);
915 Text( w->RPort, spaces, 1 );
916 amii_curs( WIN_MESSAGE, colx, bottom);
917 }
918 else
919 DisplayBeep( NULL );
920 }
921 else if( c == '\n' || c == '\r' )
922 {
923 return(sel);
924 }
925 else if( c >= ' ' && c < '\177')
926 {
927 /* avoid isprint() - some people don't have it
928 ' ' is not always a printing char */
929 *bufp = c;
930 bufp[1] = 0;
931 oindex = 0;
932 com_index = -1;
933
934 while(extcmdlist[oindex].ef_txt != NULL)
935 {
936 if(!strnicmp(obufp, (char *)extcmdlist[oindex].ef_txt, strlen(obufp)))
937 {
938 if(com_index == -1) /* No matches yet*/
939 com_index = oindex;
940 else /* More than 1 match */
941 com_index = -2;
942 }
943 oindex++;
944 }
945
946 if(com_index >= 0 && *obufp )
947 {
948 Strcpy(obufp, extcmdlist[com_index].ef_txt);
949 /* finish printing our string */
950 colx = put_ext_cmd( obufp, colx, cw, bottom );
951 bufp = obufp; /* reset it */
952 if(strlen(obufp) < BUFSZ-1 && strlen(obufp) < COLNO)
953 bufp += strlen(obufp);
954 did_comp=1;
955 sel = com_index;
956 }
957 else
958 {
959 colx = put_ext_cmd( obufp, colx, cw, bottom );
960 if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
961 bufp++;
962 }
963 }
964 else if(c == ('X'-64) || c == '\177')
965 {
966 colx = 0;
967 amii_clear_nhwindow( WIN_MESSAGE );
968 pline( "# " );
969 bufp = obufp;
970 } else
971 DisplayBeep( NULL );
972 }
973 return(-1);
974 #endif
975 }
976
977 static int
978 put_ext_cmd( obufp, colx, cw, bottom )
979 char *obufp;
980 int colx, bottom;
981 struct amii_WinDesc *cw;
982 {
983 struct Window *w = cw->win;
984 char *t;
985
986 t = (char *)alloc( strlen( obufp ) + 7 );
987 if( t != NULL )
988 {
989 if( scrollmsg )
990 {
991 sprintf( t, "xxx%s", obufp );
992 t[0] = 1;
993 t[1] = 1;
994 t[2] = '#';
995 amii_curs( WIN_MESSAGE, 0, bottom);
996 SetAPen( w->RPort, C_WHITE );
997 Text(w->RPort, "># ", 3 );
998 /* SetAPen( w->RPort, C_BLACK ); */ /* Black text on black screen doesn't look too well ... -jhsa */
999 Text(w->RPort, t+3, strlen( t ) - 3 );
1000 }
1001 else
1002 {
1003 sprintf( t, "# %s", obufp );
1004 amii_curs( WIN_MESSAGE, 0, bottom);
1005 SetAPen( w->RPort, C_WHITE );
1006 Text(w->RPort, t, strlen( t ) );
1007 }
1008 if( scrollmsg )
1009 SetAPen( w->RPort, C_WHITE );
1010 if( cw->data[ cw->maxrow - 1 ] )
1011 free( cw->data[ cw->maxrow - 1 ] );
1012 cw->data[ cw->maxrow - 1 ] = t;
1013 }
1014 else
1015 {
1016 amii_curs( WIN_MESSAGE, 0, bottom);
1017 SetAPen( w->RPort, C_WHITE );
1018 Text(w->RPort, "# ", 2 );
1019 /* SetAPen( w->RPort, C_BLACK ); */ /* Black on black ... -jhsa */
1020 Text(w->RPort, obufp, strlen( obufp ) );
1021 SetAPen( w->RPort, C_WHITE );
1022 }
1023 amii_curs( WIN_MESSAGE, colx = strlen( obufp ) + 3 + ( scrollmsg != 0 ), bottom);
1024 return( colx );
1025 }
1026
1027 /* Ask a question and get a response */
1028
1029 char amii_yn_function(query, resp, def)
1030 const char *query,*resp;
1031 char def;
1032 /*
1033 * Generic yes/no function. 'def' is the default (returned by space or
1034 * return; 'esc' returns 'q', or 'n', or the default, depending on
1035 * what's in the string. The 'query' string is printed before the user
1036 * is asked about the string.
1037 * If resp is NULL, any single character is accepted and returned.
1038 * If not-NULL, only characters in it are allowed (exceptions: the
1039 * quitchars are always allowed, and if it contains '#' then digits
1040 * are allowed); if it includes an <esc>, anything beyond that won't
1041 * be shown in the prompt to the user but will be acceptable as input.
1042 */
1043 {
1044 register char q;
1045 char rtmp[40];
1046 boolean digit_ok, allow_num;
1047 char prompt[QBUFSZ];
1048 register struct amii_WinDesc *cw;
1049
1050 if( cw = amii_wins[ WIN_MESSAGE ] )
1051 cw->disprows = 0;
1052 if (resp) {
1053 char *rb, respbuf[QBUFSZ];
1054
1055 allow_num = (index(resp, '#') != 0);
1056 Strcpy(respbuf, resp);
1057 /* any acceptable responses that follow <esc> aren't displayed */
1058 if ((rb = index(respbuf, '\033')) != 0) *rb = '\0';
1059 Sprintf(prompt, "%s [%s] ", query, respbuf);
1060 if (def) Sprintf(eos(prompt), "(%c) ", def);
1061 pline("%s", prompt);
1062 } else {
1063 amii_putstr(WIN_MESSAGE, 0, query);
1064 cursor_on(WIN_MESSAGE);
1065 q = WindowGetchar();
1066 cursor_off(WIN_MESSAGE);
1067 *rtmp = q;
1068 rtmp[ 1 ] = 0;
1069 amii_addtopl(rtmp);
1070 goto clean_up;
1071 }
1072
1073 do { /* loop until we get valid input */
1074 cursor_on(WIN_MESSAGE);
1075 q = lowc(WindowGetchar());
1076 cursor_off(WIN_MESSAGE);
1077 #if 0
1078 /* fix for PL2 */
1079 if (q == '\020') { /* ctrl-P */
1080 if(!doprev) (void) tty_doprev_message(); /* need two initially */
1081 (void) tty_doprev_message();
1082 q = (char)0;
1083 doprev = 1;
1084 continue;
1085 } else if(doprev) {
1086 tty_clear_nhwindow(WIN_MESSAGE);
1087 cw->maxcol = cw->maxrow;
1088 doprev = 0;
1089 amii_addtopl(prompt);
1090 continue;
1091 }
1092 #endif
1093 digit_ok = allow_num && isdigit(q);
1094 if (q == '\033') {
1095 if (index(resp, 'q'))
1096 q = 'q';
1097 else if (index(resp, 'n'))
1098 q = 'n';
1099 else
1100 q = def;
1101 break;
1102 } else if (index(quitchars, q)) {
1103 q = def;
1104 break;
1105 }
1106 if (!index(resp, q) && !digit_ok) {
1107 amii_bell();
1108 q = (char)0;
1109 } else if (q == '#' || digit_ok) {
1110 char z, digit_string[2];
1111 int n_len = 0;
1112 long value = 0;
1113 amii_addtopl("#"), n_len++;
1114 digit_string[1] = '\0';
1115 if (q != '#') {
1116 digit_string[0] = q;
1117 amii_addtopl(digit_string), n_len++;
1118 value = q - '0';
1119 q = '#';
1120 }
1121 do { /* loop until we get a non-digit */
1122 cursor_on(WIN_MESSAGE);
1123 z = lowc(WindowGetchar());
1124 cursor_off(WIN_MESSAGE);
1125 if (isdigit(z)) {
1126 value = (10 * value) + (z - '0');
1127 if (value < 0) break; /* overflow: try again */
1128 digit_string[0] = z;
1129 amii_addtopl(digit_string), n_len++;
1130 } else if (z == 'y' || index(quitchars, z)) {
1131 if (z == '\033') value = -1; /* abort */
1132 z = '\n'; /* break */
1133 } else if ( z == '\b') {
1134 if (n_len <= 1) { value = -1; break; }
1135 else { value /= 10; removetopl(1), n_len--; }
1136 } else {
1137 value = -1; /* abort */
1138 amii_bell();
1139 break;
1140 }
1141 } while (z != '\n');
1142 if (value > 0) yn_number = value;
1143 else if (value == 0) q = 'n'; /* 0 => "no" */
1144 else { /* remove number from top line, then try again */
1145 removetopl(n_len), n_len = 0;
1146 q = '\0';
1147 }
1148 }
1149 } while(!q);
1150
1151 if (q != '#' && q != '\033') {
1152 Sprintf(rtmp, "%c", q);
1153 amii_addtopl(rtmp);
1154 }
1155 clean_up:
1156 cursor_off(WIN_MESSAGE);
1157 clear_nhwindow(WIN_MESSAGE);
1158 return q;
1159 }
1160
1161 void
1162 amii_display_file(fn, complain)
1163 const char *fn;
1164 boolean complain;
1165 {
1166 register struct amii_WinDesc *cw;
1167 register int win;
1168 register dlb *fp;
1169 register char *t;
1170 register char buf[ 200 ];
1171
1172 if( fn == NULL )
1173 panic("NULL file name in display_file()");
1174
1175 if( ( fp = dlb_fopen( fn, RDTMODE ) ) == (dlb *)NULL )
1176 {
1177 if (complain) {
1178 sprintf( buf, "Can't display %s: %s", fn,
1179 #ifdef _DCC
1180 strerror(errno)
1181 #else
1182 # ifdef __SASC_60
1183 __sys_errlist[ errno ]
1184 # else
1185 sys_errlist[ errno ]
1186 # endif
1187 #endif
1188 );
1189 amii_addtopl( buf );
1190 }
1191 return;
1192 }
1193 win = amii_create_nhwindow( NHW_TEXT );
1194
1195 /* Set window title to file name */
1196 if( cw = amii_wins[ win ] )
1197 cw->morestr = (char *)fn;
1198
1199 while( dlb_fgets( buf, sizeof( buf ), fp ) != NULL )
1200 {
1201 if( t = index( buf, '\n' ) )
1202 *t = 0;
1203 amii_putstr( win, 0, buf );
1204 }
1205 dlb_fclose( fp );
1206
1207 /* If there were lines in the file, display those lines */
1208
1209 if( amii_wins[ win ]->cury > 0 )
1210 amii_display_nhwindow( win, TRUE );
1211
1212 amii_wins[win]->morestr = NULL; /* don't free title string */
1213 amii_destroy_nhwindow( win );
1214 }
1215
1216 /* Put a 3-D motif border around the gadget. String gadgets or those
1217 * which do not have highlighting are rendered down. Boolean gadgets
1218 * are rendered in the up position by default.
1219 */
1220
1221 void
1222 SetBorder( gd )
1223 register struct Gadget *gd;
1224 {
1225 register struct Border *bp;
1226 register short *sp;
1227 register int i, inc = -1, dec = -1;
1228 int borders = 6;
1229 int hipen = flags.amii_dripens[ SHINEPEN ], shadowpen = flags.amii_dripens[ SHADOWPEN ];
1230 #ifdef INTUI_NEW_LOOK
1231 struct DrawInfo *dip;
1232 #endif
1233
1234 #ifdef INTUI_NEW_LOOK
1235 if( IntuitionBase->LibNode.lib_Version >= 37 )
1236 {
1237 if( dip = GetScreenDrawInfo( HackScreen ) )
1238 {
1239 hipen = dip->dri_Pens[ SHINEPEN ];
1240 shadowpen = dip->dri_Pens[ SHADOWPEN ];
1241 FreeScreenDrawInfo( HackScreen, dip );
1242 }
1243 }
1244 #endif
1245 /* Allocate two border structures one for up image and one for down
1246 * image, plus vector arrays for the border lines.
1247 */
1248
1249 if( gd->GadgetType == STRGADGET )
1250 borders = 12;
1251
1252 if( ( bp = (struct Border *)alloc( ( ( sizeof( struct Border ) * 2 ) +
1253 ( sizeof( short ) * borders ) ) * 2 ) ) == NULL )
1254 {
1255 return;
1256 }
1257
1258 /* For a string gadget, we expand the border beyond the area where
1259 * the text will be entered.
1260 */
1261
1262 /* Remove any special rendering flags to avoid confusing intuition
1263 */
1264
1265 gd->Flags &= ~(GADGHIGHBITS|GADGIMAGE);
1266
1267 sp = (short *)(bp + 4);
1268 if( gd->GadgetType == STRGADGET || ( gd->GadgetType == BOOLGADGET &&
1269 ( gd->Flags & GADGHIGHBITS ) == GADGHNONE ) )
1270 {
1271 sp[0] = -1;
1272 sp[1] = gd->Height - 1;
1273 sp[2] = -1;
1274 sp[3] = -1;
1275 sp[4] = gd->Width - 1;
1276 sp[5] = -1;
1277
1278 sp[6] = gd->Width + 1;
1279 sp[7] = -2;
1280 sp[8] = gd->Width + 1;
1281 sp[9] = gd->Height + 1;
1282 sp[10] = -2;
1283 sp[11] = gd->Height + 1;
1284
1285 sp[12] = -2;
1286 sp[13] = gd->Height;
1287 sp[14] = -2;
1288 sp[15] = -2;
1289 sp[16] = gd->Width;
1290 sp[17] = -2;
1291 sp[18] = gd->Width;
1292 sp[19] = gd->Height;
1293 sp[20] = -2;
1294 sp[21] = gd->Height;
1295
1296 for( i = 0; i < 3; ++i )
1297 {
1298 bp[ i ].LeftEdge = bp[ i ].TopEdge = -1;
1299 bp[ i ].FrontPen = ( i == 0 || i == 1 ) ? shadowpen : hipen;
1300
1301 /* Have to use JAM2 so that the old colors disappear. */
1302 bp[ i ].BackPen = C_BLACK;
1303 bp[ i ].DrawMode = JAM2;
1304 bp[ i ].Count = ( i == 0 || i == 1 ) ? 3 : 5;
1305 bp[ i ].XY = &sp[ i*6 ];
1306 bp[ i ].NextBorder = ( i == 2 ) ? NULL : &bp[ i + 1 ];
1307 }
1308
1309 /* bp[0] and bp[1] two pieces for the up image */
1310 gd->GadgetRender = (APTR) bp;
1311
1312 /* No image change for select */
1313 gd->SelectRender = (APTR) bp;
1314
1315 gd->LeftEdge++;
1316 gd->TopEdge++;
1317 gd->Flags |= GADGHCOMP;
1318 }
1319 else
1320 {
1321 /* Create the border vector values for up and left side, and
1322 * also the lower and right side.
1323 */
1324
1325 sp[0] = dec;
1326 sp[1] = gd->Height + inc;
1327 sp[2] = dec;
1328 sp[3] = dec;
1329 sp[4] = gd->Width + inc;
1330 sp[5] = dec;
1331
1332 sp[6] = gd->Width + inc;
1333 sp[7] = dec;
1334 sp[8] = gd->Width + inc;
1335 sp[9] = gd->Height + inc;
1336 sp[10] = dec;
1337 sp[11] = gd->Height + inc;
1338
1339 /* We are creating 4 sets of borders, the two sides of the
1340 * rectangle share the border vectors with the opposite image,
1341 * but specify different colors.
1342 */
1343
1344 for( i = 0; i < 4; ++i )
1345 {
1346 bp[ i ].TopEdge = bp[ i ].LeftEdge = 0;
1347
1348 /* A GADGHNONE is always down */
1349
1350 if( gd->GadgetType == BOOLGADGET &&
1351 ( gd->Flags & GADGHIGHBITS ) != GADGHNONE )
1352 {
1353 bp[ i ].FrontPen =
1354 ( i == 1 || i == 2 ) ? shadowpen : hipen;
1355 }
1356 else
1357 {
1358 bp[ i ].FrontPen =
1359 ( i == 1 || i == 3 ) ? hipen : shadowpen;
1360 }
1361
1362 /* Have to use JAM2 so that the old colors disappear. */
1363 bp[ i ].BackPen = C_BLACK;
1364 bp[ i ].DrawMode = JAM2;
1365 bp[ i ].Count = 3;
1366 bp[ i ].XY = &sp[ 6 * ((i &1) != 0) ];
1367 bp[ i ].NextBorder =
1368 ( i == 1 || i == 3 ) ? NULL : &bp[ i + 1 ];
1369 }
1370
1371 /* bp[0] and bp[1] two pieces for the up image */
1372 gd->GadgetRender = (APTR) bp;
1373
1374 /* bp[2] and bp[3] two pieces for the down image */
1375 gd->SelectRender = (APTR) (bp + 2);
1376 gd->Flags |= GADGHIMAGE;
1377 }
1378 }
1379
1380 /* Following function copied from wintty.c */
1381 /* Modified slightly to fit amiga needs */
1382
1383 void
1384 amii_player_selection()
1385 {
1386 int i, k, n;
1387 char pick4u = 'n', thisch, lastch = 0;
1388 char pbuf[QBUFSZ];
1389 winid win;
1390 anything any;
1391 menu_item *selected = 0;
1392
1393 /* Should we randomly pick for the player? */
1394 if (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE ||
1395 flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE) {
1396 const char *prompt = "Shall I pick a character for you?";
1397 pick4u = amii_yn_function(prompt, "ynq", 'y');
1398
1399 if (pick4u != 'y' && pick4u != 'n') {
1400 give_up: /* Quit */
1401 if (selected) free((genericptr_t) selected);
1402 exit_nhwindows(NULL);
1403 terminate(0);
1404 /*NOTREACHED*/
1405 return;
1406 }
1407 }
1408
1409 /* Select a role, if necessary */
1410 /* we'll try to be compatible with pre-selected race/gender/alignment,
1411 * but may not succeed */
1412 if (flags.initrole < 0) {
1413 /* Process the choice */
1414 if (pick4u == 'y' || flags.initrole == ROLE_RANDOM) {
1415 /* Pick a random role */
1416 flags.initrole = pick_role(flags.initrace, flags.initgend,
1417 flags.initalign);
1418 if (flags.initrole < 0) {
1419 amii_putstr(WIN_MESSAGE, 0, "Incompatible role!");
1420 flags.initrole = randrole();
1421 }
1422 } else {
1423 /* Prompt for a role */
1424 win = create_nhwindow(NHW_MENU);
1425 start_menu(win);
1426 any.a_void = 0; /* zero out all bits */
1427 for (i = 0; roles[i].name.m; i++) {
1428 if (ok_role(i, flags.initrace, flags.initgend,
1429 flags.initalign)) {
1430 any.a_int = i+1; /* must be non-zero */
1431 thisch = lowc(roles[i].name.m[0]);
1432 if (thisch == lastch) thisch = highc(thisch);
1433 add_menu(win, NO_GLYPH, &any, thisch,
1434 0, ATR_NONE, an(roles[i].name.m), MENU_UNSELECTED);
1435 lastch = thisch;
1436 }
1437 }
1438 any.a_int = pick_role(flags.initrace, flags.initgend,
1439 flags.initalign)+1;
1440 if (any.a_int == 0) /* must be non-zero */
1441 any.a_int = randrole()+1;
1442 add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
1443 "Random", MENU_UNSELECTED);
1444 any.a_int = i+1; /* must be non-zero */
1445 add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
1446 "Quit", MENU_UNSELECTED);
1447 end_menu(win, "Pick a role");
1448 n = select_menu(win, PICK_ONE, &selected);
1449 destroy_nhwindow(win);
1450
1451 /* Process the choice */
1452 if (n != 1 || selected[0].item.a_int == any.a_int)
1453 goto give_up; /* Selected quit */
1454
1455 flags.initrole = selected[0].item.a_int - 1;
1456 free((genericptr_t) selected), selected = 0;
1457 }
1458 }
1459
1460 /* Select a race, if necessary */
1461 /* force compatibility with role, try for compatibility with
1462 * pre-selected gender/alignment */
1463 if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
1464 /* pre-selected race not valid */
1465 if (pick4u == 'y' || flags.initrace == ROLE_RANDOM) {
1466 flags.initrace = pick_race(flags.initrole, flags.initgend,
1467 flags.initalign);
1468 if (flags.initrace < 0) {
1469 amii_putstr(WIN_MESSAGE, 0, "Incompatible race!");
1470 flags.initrace = randrace(flags.initrole);
1471 }
1472 } else { /* pick4u == 'n' */
1473 /* Count the number of valid races */
1474 n = 0; /* number valid */
1475 k = 0; /* valid race */
1476 for (i = 0; races[i].noun; i++) {
1477 if (ok_race(flags.initrole, i, flags.initgend,
1478 flags.initalign)) {
1479 n++;
1480 k = i;
1481 }
1482 }
1483 if (n == 0) {
1484 for (i = 0; races[i].noun; i++) {
1485 if (validrace(flags.initrole, i)) {
1486 n++;
1487 k = i;
1488 }
1489 }
1490 }
1491
1492 /* Permit the user to pick, if there is more than one */
1493 if (n > 1) {
1494 win = create_nhwindow(NHW_MENU);
1495 start_menu(win);
1496 any.a_void = 0; /* zero out all bits */
1497 for (i = 0; races[i].noun; i++)
1498 if (ok_race(flags.initrole, i, flags.initgend,
1499 flags.initalign)) {
1500 any.a_int = i+1; /* must be non-zero */
1501 add_menu(win, NO_GLYPH, &any, races[i].noun[0],
1502 0, ATR_NONE, races[i].noun, MENU_UNSELECTED);
1503 }
1504 any.a_int = pick_race(flags.initrole, flags.initgend,
1505 flags.initalign)+1;
1506 if (any.a_int == 0) /* must be non-zero */
1507 any.a_int = randrace(flags.initrole)+1;
1508 add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
1509 "Random", MENU_UNSELECTED);
1510 any.a_int = i+1; /* must be non-zero */
1511 add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
1512 "Quit", MENU_UNSELECTED);
1513 Sprintf(pbuf, "Pick the race of your %s",
1514 roles[flags.initrole].name.m);
1515 end_menu(win, pbuf);
1516 n = select_menu(win, PICK_ONE, &selected);
1517 destroy_nhwindow(win);
1518 if (n != 1 || selected[0].item.a_int == any.a_int)
1519 goto give_up; /* Selected quit */
1520
1521 k = selected[0].item.a_int - 1;
1522 free((genericptr_t) selected), selected = 0;
1523 }
1524 flags.initrace = k;
1525 }
1526 }
1527
1528 /* Select a gender, if necessary */
1529 /* force compatibility with role/race, try for compatibility with
1530 * pre-selected alignment */
1531 if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
1532 flags.initgend)) {
1533 /* pre-selected gender not valid */
1534 if (pick4u == 'y' || flags.initgend == ROLE_RANDOM) {
1535 flags.initgend = pick_gend(flags.initrole, flags.initrace,
1536 flags.initalign);
1537 if (flags.initgend < 0) {
1538 amii_putstr(WIN_MESSAGE, 0, "Incompatible gender!");
1539 flags.initgend = randgend(flags.initrole, flags.initrace);
1540 }
1541 } else { /* pick4u == 'n' */
1542 /* Count the number of valid genders */
1543 n = 0; /* number valid */
1544 k = 0; /* valid gender */
1545 for (i = 0; i < ROLE_GENDERS; i++) {
1546 if (ok_gend(flags.initrole, flags.initrace, i,
1547 flags.initalign)) {
1548 n++;
1549 k = i;
1550 }
1551 }
1552 if (n == 0) {
1553 for (i = 0; i < ROLE_GENDERS; i++) {
1554 if (validgend(flags.initrole, flags.initrace, i)) {
1555 n++;
1556 k = i;
1557 }
1558 }
1559 }
1560
1561 /* Permit the user to pick, if there is more than one */
1562 if (n > 1) {
1563 win = create_nhwindow(NHW_MENU);
1564 start_menu(win);
1565 any.a_void = 0; /* zero out all bits */
1566 for (i = 0; i < ROLE_GENDERS; i++)
1567 if (ok_gend(flags.initrole, flags.initrace, i,
1568 flags.initalign)) {
1569 any.a_int = i+1;
1570 add_menu(win, NO_GLYPH, &any, genders[i].adj[0],
1571 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED);
1572 }
1573 any.a_int = pick_gend(flags.initrole, flags.initrace,
1574 flags.initalign)+1;
1575 if (any.a_int == 0) /* must be non-zero */
1576 any.a_int = randgend(flags.initrole, flags.initrace)+1;
1577 add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
1578 "Random", MENU_UNSELECTED);
1579 any.a_int = i+1; /* must be non-zero */
1580 add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
1581 "Quit", MENU_UNSELECTED);
1582 Sprintf(pbuf, "Pick the gender of your %s %s",
1583 races[flags.initrace].adj,
1584 roles[flags.initrole].name.m);
1585 end_menu(win, pbuf);
1586 n = select_menu(win, PICK_ONE, &selected);
1587 destroy_nhwindow(win);
1588 if (n != 1 || selected[0].item.a_int == any.a_int)
1589 goto give_up; /* Selected quit */
1590
1591 k = selected[0].item.a_int - 1;
1592 free((genericptr_t) selected), selected = 0;
1593 }
1594 flags.initgend = k;
1595 }
1596 }
1597
1598 /* Select an alignment, if necessary */
1599 /* force compatibility with role/race/gender */
1600 if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
1601 flags.initalign)) {
1602 /* pre-selected alignment not valid */
1603 if (pick4u == 'y' || flags.initalign == ROLE_RANDOM) {
1604 flags.initalign = pick_align(flags.initrole, flags.initrace,
1605 flags.initgend);
1606 if (flags.initalign < 0) {
1607 amii_putstr(WIN_MESSAGE, 0, "Incompatible alignment!");
1608 flags.initalign = randalign(flags.initrole, flags.initrace);
1609 }
1610 } else { /* pick4u == 'n' */
1611 /* Count the number of valid alignments */
1612 n = 0; /* number valid */
1613 k = 0; /* valid alignment */
1614 for (i = 0; i < ROLE_ALIGNS; i++) {
1615 if (ok_align(flags.initrole, flags.initrace, flags.initgend,
1616 i)) {
1617 n++;
1618 k = i;
1619 }
1620 }
1621 if (n == 0) {
1622 for (i = 0; i < ROLE_ALIGNS; i++) {
1623 if (validalign(flags.initrole, flags.initrace, i)) {
1624 n++;
1625 k = i;
1626 }
1627 }
1628 }
1629
1630 /* Permit the user to pick, if there is more than one */
1631 if (n > 1) {
1632 win = create_nhwindow(NHW_MENU);
1633 start_menu(win);
1634 any.a_void = 0; /* zero out all bits */
1635 for (i = 0; i < ROLE_ALIGNS; i++)
1636 if (ok_align(flags.initrole, flags.initrace,
1637 flags.initgend, i)) {
1638 any.a_int = i+1;
1639 add_menu(win, NO_GLYPH, &any, aligns[i].adj[0],
1640 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
1641 }
1642 any.a_int = pick_align(flags.initrole, flags.initrace,
1643 flags.initgend)+1;
1644 if (any.a_int == 0) /* must be non-zero */
1645 any.a_int = randalign(flags.initrole, flags.initrace)+1;
1646 add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
1647 "Random", MENU_UNSELECTED);
1648 any.a_int = i+1; /* must be non-zero */
1649 add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
1650 "Quit", MENU_UNSELECTED);
1651 Sprintf(pbuf, "Pick the alignment of your %s %s %s",
1652 genders[flags.initgend].adj,
1653 races[flags.initrace].adj,
1654 (flags.initgend && roles[flags.initrole].name.f) ?
1655 roles[flags.initrole].name.f :
1656 roles[flags.initrole].name.m);
1657 end_menu(win, pbuf);
1658 n = select_menu(win, PICK_ONE, &selected);
1659 destroy_nhwindow(win);
1660 if (n != 1 || selected[0].item.a_int == any.a_int)
1661 goto give_up; /* Selected quit */
1662
1663 k = selected[0].item.a_int - 1;
1664 free((genericptr_t) selected), selected = 0;
1665 }
1666 flags.initalign = k;
1667 }
1668 }
1669 /* Success! */
1670 }
1671 #endif /* AMIGA_INTUITION */
1672