home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / sys / mac / macmain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-01  |  12.9 KB  |  597 lines  |  [TEXT/R*ch]

  1. /*    SCCS Id: @(#)macmain.c    3.1    92/12/04    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /* main.c - Mac NetHack */
  6.  
  7. #include "hack.h"
  8.  
  9. #include <OSUtils.h>
  10. #include <files.h>
  11. #include <Types.h>
  12. #ifdef MAC_MPW32
  13. #include <String.h>
  14. #include <Strings.h>
  15. #endif
  16. #include <Dialogs.h>
  17. #include <Packages.h>
  18. #include <ToolUtils.h>
  19. #include <Resources.h>
  20. #ifndef THINK_C
  21. #include <SysEqu.h>
  22. #endif
  23. #include <Errors.h>
  24.  
  25. #ifndef O_RDONLY
  26. #include <fcntl.h>
  27. #endif
  28.  
  29. extern void    DialogAskName(asknameRec *);
  30.  
  31. int NDECL(main);
  32. void NDECL(ListGUnloads);
  33.  
  34. static void NDECL(process_options);
  35. static void NDECL(whoami);
  36.  
  37. extern char * PtoCstr ( unsigned char * ) ;
  38. extern unsigned char * CtoPstr ( char * ) ;
  39. void SetFrameItem ( DialogPtr , short , short ) ;
  40.  
  41. extern void NDECL ( finder_file_request ) ;
  42. // void NDECL( askname ) ;
  43.  
  44. extern void NDECL ( InitMac ) ;
  45.  
  46. int
  47. main ( void )
  48. {
  49.     register int fd;
  50.  
  51.     windowprocs = mac_procs ;
  52.     InitMac ( ) ;
  53.  
  54.     hname = "Mac Hack" ;
  55.     hackpid = getpid();
  56.  
  57.     initoptions();
  58.     init_nhwindows();
  59.     whoami();
  60.  
  61.     /*
  62.      * It seems you really want to play.
  63.      */
  64.     setrandom();
  65.     u.uhp = 1;    /* prevent RIP on early quits */
  66.  
  67.     process_options ( ) ;    /* emulate command line options */
  68.     finder_file_request ( ) ;
  69.  
  70. #ifdef WIZARD
  71.     if (wizard)
  72.         Strcpy(plname, "wizard");
  73.     else
  74. #endif
  75.     if(!*plname || !strncmp(plname, "player", 4)
  76.             || !strncmp(plname, "games", 4))
  77.         askname();
  78.     plnamesuffix();        /* strip suffix from name; calls askname() */
  79.                 /* again if suffix was whole name */
  80.                 /* accepts any suffix */
  81.  
  82.     Sprintf ( lock , "%d%s" , getuid ( ) , plname ) ;
  83.     getlock ( ) ;
  84.  
  85.     /*
  86.      * Initialisation of the boundaries of the mazes
  87.      * Both boundaries have to be even.
  88.      */
  89.  
  90.     x_maze_max = COLNO-1;
  91.     if (x_maze_max % 2)
  92.         x_maze_max--;
  93.     y_maze_max = ROWNO-1;
  94.     if (y_maze_max % 2)
  95.         y_maze_max--;
  96.  
  97.     /*
  98.      *  Initialize the vision system.  This must be before mklev() on a
  99.      *  new game or before a level restore on a saved game.
  100.      */
  101.     vision_init();
  102.  
  103.     display_gamewindows();
  104.  
  105.     set_savefile_name();
  106.     uncompress(SAVEF);
  107.  
  108.     if((fd = open_savefile()) >= 0 &&
  109.        /* if not up-to-date, quietly delete file via false condition */
  110.        (uptodate(fd) || delete_savefile())) {
  111. #ifdef WIZARD
  112.         /* Since wizard is actually flags.debug, restoring might
  113.          * overwrite it.
  114.          */
  115.         boolean remember_wiz_mode = wizard;
  116. #endif
  117. #ifdef NEWS
  118.         if(flags.news) {
  119.             display_file(NEWS, FALSE);
  120.             flags.news = FALSE;    /* in case dorecover() fails */
  121.         }
  122. #endif
  123.         pline("Restoring save file...");
  124.         mark_synch();    /* flush output */
  125.         if(!dorecover(fd))
  126.             goto not_recovered;
  127. #ifdef WIZARD
  128.         if(!wizard && remember_wiz_mode) wizard = TRUE;
  129. #endif
  130.         pline("Hello %s, welcome back to NetHack!", plname);
  131.         check_special_room(FALSE);
  132.  
  133. #ifdef EXPLORE_MODE
  134.         if (discover)
  135.             You("are in non-scoring discovery mode.");
  136. #endif
  137. #if defined(EXPLORE_MODE) || defined(WIZARD)
  138.         if (discover || wizard) {
  139.             if(yn("Do you want to keep the save file?") == 'n')
  140.                 (void) delete_savefile();
  141.             else {
  142.                 compress(SAVEF);
  143.             }
  144.         }
  145. #endif
  146.         flags.move = 0;
  147.     } else {
  148. not_recovered:
  149.         player_selection();
  150.         newgame();
  151.         /* give welcome message before pickup messages */
  152.         pline("Hello %s, welcome to NetHack!", plname);
  153. #ifdef EXPLORE_MODE
  154.         if (discover)
  155.             You("are in non-scoring discovery mode.");
  156. #endif
  157.         flags.move = 0;
  158.         set_wear();
  159.         pickup(1);
  160.     }
  161.  
  162.     flags.moonphase = phase_of_the_moon();
  163.     if(flags.moonphase == FULL_MOON) {
  164.         You("are lucky!  Full moon tonight.");
  165.         change_luck(1);
  166.     } else if(flags.moonphase == NEW_MOON) {
  167.         pline("Be careful!  New moon tonight.");
  168.     }
  169.     if(flags.friday13 = friday_13th()) {
  170.         pline("Watch out!  Bad things can happen on Friday the 13th.");
  171.         change_luck(-1);
  172.     }
  173.  
  174.     initrack();
  175.  
  176.     UndimMenuBar ( ) ; /* Yes, this is the place for it (!) */
  177.     
  178.     attemptingto("proceed");
  179. #if defined(MAC_MPW32) && !defined(MODEL_FAR)
  180.     UnloadAllSegments();                        /* Do this before naming residents */
  181.     IsResident( (Ptr) um_dist );                /* Sample resident segments */
  182.     IsResident( (Ptr) flush_screen );
  183.     IsResident( (Ptr) rhack );
  184.     IsResident( (Ptr) remove_cadavers );
  185.     IsResident( (Ptr) dog_move );
  186.     IsResident( (Ptr) gethungry );
  187.     IsResident( (Ptr) engr_at );
  188.     IsResident( (Ptr) domove );
  189.     IsResident( (Ptr) carried );
  190.     IsResident( (Ptr) movemon );
  191.     IsResident( (Ptr) attacktype ) ;
  192.     IsResident( (Ptr) mac_get_nh_event ) ;
  193.     IsResident( (Ptr) dosounds ) ;
  194.     IsResident( (Ptr) t_at ) ;
  195.     IsResident( (Ptr) nh_timeout ) ;
  196. #endif
  197.     moveloop();
  198.     /*NOTREACHED*/
  199.     return 0;
  200. }
  201.  
  202.  
  203. /*
  204.  * This filter handles the movable-modal dialog
  205.  *
  206.  */
  207. static pascal Boolean
  208. DragFilter ( DialogPtr dp , EventRecord * event , short * item )
  209. {
  210.     WindowPtr wp ;
  211.     short code ;
  212.     Rect r ;
  213.  
  214. /*
  215.  *    Handle shortcut keys
  216.  *    enter, return -> OK
  217.  *    clear, escape, period -> Cancel
  218.  *    all others are handled default
  219.  *
  220.  */
  221.  
  222.     if ( event -> what == keyDown ) {
  223.  
  224.         char c = event -> message & 0xff ;
  225.         unsigned char b = ( event -> message >> 8 ) & 0xff ;
  226.  
  227.         switch ( c ) {
  228.  
  229.         case 3 :    /* 3 == Enter */
  230.         case 10 :    /* Newline */
  231.         case 13 :    /* Return */
  232.             * item = 1 ;
  233.             return 1 ;
  234.  
  235.         case '.' :    /* Cmd-period - we allow only period */
  236.         case 27 :    /* Escape */
  237.             * item = 2 ;
  238.             return 1 ;
  239.         }
  240.  
  241.         switch ( b ) {
  242.  
  243.         case 0x4c :    /* Enter */
  244.         case 0x24 :    /* Return */
  245.             * item = 1 ;
  246.             return 1 ;
  247.  
  248.         case 0x35 :    /* Escape */
  249.         case 0x47 :    /* Clear */
  250.             * item = 2 ;
  251.             return 1 ;
  252.         }
  253.  
  254.         return 0 ;
  255.     }
  256.  
  257. /*
  258.  *    OK, don't handle others
  259.  *
  260.  */
  261.  
  262.     if ( event -> what != mouseDown ) {
  263.  
  264.         return 0 ;
  265.     }
  266.     code = FindWindow ( event -> where , & wp ) ;
  267.     if ( wp != dp || code != inDrag ) {
  268.  
  269.         return 0 ;
  270.     }
  271.     r = ( * GetGrayRgn ( ) ) -> rgnBBox ;
  272.     InsetRect ( & r , 3 , 3 ) ;
  273.  
  274.     DragWindow ( wp , event -> where , & r ) ;
  275.     SaveWindowPos ( wp ) ;
  276.  
  277.     event -> what = nullEvent ;
  278.     return 1 ;
  279. }
  280.  
  281.  
  282. /*
  283.  * plname is filled either by an option (-u Player  or  -uPlayer) or
  284.  * explicitly (by being the wizard) or by askname.
  285.  * It may still contain a suffix denoting pl_character.
  286.  */
  287. void
  288. mac_askname(void) /* Code taken from getlin */
  289. {
  290.     asknameRec    anr;
  291.     /* eventually use roles[] a/o pl_classes[] */
  292.     static char        asknRoles [ ] = "ABCEHKPRSTVW" ;
  293.  
  294.     /* initialize the askname record */
  295.     qd.randSeed = TickCount() ;
  296.     anr.anMenu[anRole] = (Random ( ) & 0x7fff ) % askn_role_end;
  297.  
  298. #ifndef TOURIST
  299.     if (anr.anMenu[anRole] == asknTourist) {
  300.         anr.anMenu[anRole] = asknValkyrie;
  301.     }
  302. #endif
  303.  
  304.     if (anr.anMenu[anRole] == asknValkyrie) {
  305.         anr.anMenu[anSex] = asknFemale;
  306.     } else {
  307.         anr.anMenu[anSex] = ( (Random() & 2) ? asknMale : asknFemale);
  308.     }
  309.  
  310.     anr.anMenu[anMode] = asknRegular;
  311.  
  312.     InitCursor();
  313.     DialogAskName(&anr);
  314.  
  315.     if (anr.anMenu[anMode] == asknQuit) {
  316.         ExitToShell();
  317.     }
  318.  
  319. #ifdef EXPLORE_MODE
  320.     if (anr.anMenu[anMode] == asknExplore ) {
  321.         discover = 1 ;
  322.     } else {
  323.         discover = 0 ;
  324.     }
  325. #endif
  326.  
  327. #ifdef WIZARD
  328.     if ( anr.anMenu [ anMode ] == asknDebug ) {
  329.         wizard = 1 ;
  330.     } else {
  331.         wizard = 0 ;
  332.     }
  333.     if (wizard) {
  334.         strcpy(plname, WIZARD);
  335.     } else
  336. #endif
  337.     {
  338.         BlockMove(&(anr.anWho[1]), plname, anr.anWho[0]);
  339.         plname [ anr . anWho [ 0 ] ] = 0 ;
  340.     }
  341.  
  342.     flags.female = anr.anMenu[anSex];
  343.     pl_character[0] = asknRoles[anr.anMenu[anRole]];
  344. }
  345.  
  346.  
  347. static void
  348. process_options(void)
  349. {
  350.     int argc = 0 ;
  351.     char * foo [ ] = { "Mac Hack" , NULL } ;
  352.     char * * argv = foo ;
  353.     /*
  354.      * Process options.
  355.      */
  356.     while(argc > 1 && argv[1][0] == '-'){
  357.         argv++;
  358.         argc--;
  359.         switch(argv[0][1]){
  360. #if defined(WIZARD) || defined(EXPLORE_MODE)
  361. # ifndef EXPLORE_MODE
  362.         case 'X':
  363. # endif
  364.         case 'D':
  365. # ifdef WIZARD
  366.             wizard = TRUE ;
  367.             break ;
  368. # endif
  369. # ifdef EXPLORE_MODE
  370.         case 'X':
  371.             discover = TRUE;
  372. # endif
  373.             break;
  374. #endif
  375. #ifdef NEWS
  376.         case 'n':
  377.             flags.news = FALSE;
  378.             break;
  379. #endif
  380.         case 'u':
  381.             if(argv[0][2])
  382.               (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
  383.             else if(argc > 1) {
  384.               argc--;
  385.               argv++;
  386.               (void) strncpy(plname, argv[0], sizeof(plname)-1);
  387.             } else
  388.                 raw_print("Player name expected after -u");
  389.             break;
  390.         case 'I':
  391.         case 'i':
  392.             if (!strncmpi(argv[0]+1, "IBM", 3))
  393.                 switch_graphics(IBM_GRAPHICS);
  394.             break;
  395.         /*  case 'D': */
  396.         case 'd':
  397.             if (!strncmpi(argv[0]+1, "DEC", 3))
  398.                 switch_graphics(DEC_GRAPHICS);
  399.             break;
  400.         default:
  401.             /* allow -T for Tourist, etc. */
  402.             (void) strncpy(pl_character, argv[0]+1,
  403.                 sizeof(pl_character)-1);
  404.  
  405.             /* raw_print("Unknown option: %s", *argv); */
  406.         }
  407.     }
  408. }
  409.  
  410.  
  411. static void
  412. whoami ( void )
  413. {
  414.     /*TODO*/
  415.     donull ( ) ;
  416. }
  417.  
  418.  
  419. /*------------------- UnloadAllSegments and support stuff --------------------------*/
  420. /* Derived from MacApp source */
  421.  
  422. typedef Handle **HandleListHandle;
  423. typedef Boolean **BoolListHandle;
  424. typedef short *ShortPtr, **ShortHandle;
  425.  
  426. short FDECL(GetSegNumber,(ShortPtr));
  427. void FDECL(InitSegMgmt,(void *));
  428. pascal long NDECL(GetA5);
  429. pascal short NDECL(GetCurJTOffset);
  430. void NDECL(UnloadAllSegments);
  431. void FDECL(IsResident,(void *));
  432. void FDECL(NotResident, (void *));
  433.  
  434. short              pMaxSegNum = 0,        /* Highest segment number */
  435.                    gCodeRefNum;            /* rsrc refnum of the application */
  436. HandleListHandle gCodeSegs;                /* List of code seg handles */
  437. BoolListHandle   gIsResidentSeg;        /* Resident flags */
  438.  
  439. #define kLoaded   0x4EF9                /* if loaded then a JMP instruction */
  440. #define    kUnLoaded 0x3F3C                /* if unloaded then a LoadSeg trap */
  441.                                         /* Note: probably incorrect for -model far! */
  442.  
  443. /* #define TRACKSEGS /* Utility to print a trace of segment load frequencies. */
  444.  
  445. #ifdef TRACKSEGS
  446.  
  447. long      gUnloads[120];
  448. char      gSegNames[120][16];
  449.  
  450. void ListGUnloads(void)
  451. {
  452.   int i;
  453.   FILE *f;
  454.   
  455.   f = fopen("unloads","w");
  456.   fprintf(f,"%d calls to UnloadAllSegments\n\n",gUnloads[0]);
  457.   for (i=1; i<=pMaxSegNum; i++) {
  458.      fprintf(f,"Unloaded %10s, segment %2d, %6d times\n",gSegNames[i],i,gUnloads[i]);
  459.   }
  460.   fclose(f);
  461. }
  462.  
  463. #endif
  464.  
  465. short GetSegNumber(ShortPtr aProc)
  466. /* Derives seg number from a procedure ptr */
  467.  
  468. {
  469.     if (*aProc == kLoaded)                 /* loaded segment */
  470.         return(*--aProc);
  471.     else if (*aProc == kUnLoaded)          /* unloaded segment */
  472.         return(*++aProc);
  473.     else {
  474.         progerror("GetSegNumber was not passed an jump table address");
  475.         return(1);
  476.     }
  477. }
  478.  
  479. void InitSegMgmt(void * mainSeg)
  480. /* Initialise a list of handles to all the CODE segments and mark the mainseg as resident */
  481. {
  482.     short     i,
  483.             lastRsrc,
  484.             rsrcID,
  485.             oldResFile;
  486.     Handle  seg;
  487.     ResType rsrcType;
  488.     Str255  rsrcName;
  489.      
  490.     gCodeRefNum = HomeResFile(GetResource('CODE', 1));    
  491.     oldResFile = CurResFile();
  492.     UseResFile(gCodeRefNum);
  493.     
  494.     /* Discover the highest CODE rsrc ID: be ready for noncontiguous IDs */
  495.     lastRsrc = Count1Resources('CODE');    
  496.     SetResLoad(false);
  497.     for (i=1; i<=lastRsrc; i++) 
  498.         if (seg = Get1IndResource('CODE', i)) {
  499.             GetResInfo(seg, &rsrcID, &rsrcType, rsrcName);
  500.             if (rsrcID > pMaxSegNum) pMaxSegNum = rsrcID;
  501.         }
  502.         
  503.     /* Make handles of appropriate size to keep flags/segment handles */
  504.     SetResLoad(true);  /* In case we fail */
  505.     gCodeSegs = (HandleListHandle) NewHandle((pMaxSegNum+1) * sizeof(Handle));    
  506.     mustwork(MemError());
  507.     gIsResidentSeg = (BoolListHandle) NewHandle((pMaxSegNum+1) * sizeof(Boolean));
  508.     mustwork(MemError());
  509.     SetResLoad(false);    
  510.  
  511.     #ifdef TRACKSEGS
  512.     atexit(&ListGUnloads);
  513.     gUnloads[0]=0;
  514.     #endif
  515.     for (i=1; i<=pMaxSegNum; i++) {
  516.        (*gIsResidentSeg)[i] = false;
  517.        (*gCodeSegs)[i] = Get1Resource('CODE',i);   /* Will be NIL if it doesn't exist */
  518.        #ifdef TRACKSEGS
  519.        {  /* Go get the segment name and save it */
  520.           short id;
  521.           ResType rType;
  522.           Str255 name;
  523.           char *cptr;
  524.           
  525.           GetResInfo((*gCodeSegs)[i],&id,&rType,&name);
  526.           if (name[0]>15) name[0]=15;
  527.           cptr = p2cstr(&name);
  528.           cptr = strcpy(&gSegNames[i], &name);
  529.           gUnloads[i] = 0;
  530.        }
  531.        #endif
  532.     }
  533.     SetResLoad(true);    
  534.     (*gIsResidentSeg)[GetSegNumber((ShortPtr)mainSeg)] = true;    
  535.     UseResFile(oldResFile);
  536. }
  537.  
  538. #ifdef MAC_MPW32
  539. pascal long GetA5(void) = { 0x2E8D };                    /* MOVE.L A5,(A7) */
  540. pascal short GetCurJTOffset(void) = { 0x3EB8, 0x934 };   /* MOVE.W CurJTOffset,(SP) */
  541. #endif
  542. #ifdef THINK_C
  543. pascal long GetA5(void) = { 0x2E8D };                    /* MOVE.L A5,(A7) */
  544. pascal short GetCurJTOffset(void) = { 0x3EB8, 0x934 };   /* MOVE.W CurJTOffset,(SP) */
  545. #endif
  546.  
  547. void UnloadAllSegments(void)
  548. {
  549.   short     i,
  550.          oldResFile;
  551.   Handle seg;
  552.   long     jumpTablePtr;
  553.  
  554.   jumpTablePtr = GetA5() + GetCurJTOffset();
  555.   oldResFile = CurResFile();
  556.   UseResFile(gCodeRefNum);
  557. #ifdef TRACKSEGS
  558.   gUnloads[0]++;
  559. #endif
  560.   for (i=1; i<=pMaxSegNum; i++)
  561.       if (!(*gIsResidentSeg)[i]) {
  562.           seg = (*gCodeSegs)[i];
  563.           if ((seg != (Handle) nil) && (*seg != (Ptr) nil))  /* Check it exists and hasn't been purged */
  564.               if (HGetState(seg) & 0x80)  {   /* Is it locked? => loaded */
  565. #ifdef TRACKSEGS
  566.                  gUnloads[i]++;
  567. #endif
  568.                  UnloadSeg( (void *) (jumpTablePtr + **(ShortHandle)seg + 2) );
  569.               }
  570.       }
  571.  
  572.   UseResFile(oldResFile);
  573. }
  574.  
  575. void IsResident( void * routineaddr )
  576. /* We want to move this high up in the heap as it won't be shifted again, so... */
  577. {
  578.     int    segnum;
  579.     Handle theseg;
  580.     
  581.     segnum = GetSegNumber((ShortPtr)routineaddr);
  582.     theseg = (*gCodeSegs)[segnum];
  583.     UnloadSeg( routineaddr );
  584.     if (*theseg != nil) {
  585.        MoveHHi( theseg );  /* If it has been purged we can't do this */
  586.        HLock( theseg );
  587.     }
  588.     (*gIsResidentSeg)[segnum] = true;    
  589. }
  590.  
  591. void NotResident( void * routineaddr )
  592. {
  593.     (*gIsResidentSeg)[GetSegNumber((ShortPtr)routineaddr)] = false;    
  594. }
  595.  
  596. /*macmain.c*/
  597.