home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / gfx / megajitter-1.3.lha / MegaJitter-1.3 / mj.c < prev    next >
Text File  |  1994-05-19  |  92KB  |  3,039 lines

  1. //----------------------------------------------------------------------
  2. // MegaJitter V1.3        written by L. Vanhelsuwé        (C) LVA 1992-94
  3. // ---------- ----        ------------------------        ---------------
  4. // Based on a slower program called "Jitter" (authors "Don & Chris").
  5. //
  6. // Graphical evolution simulator.
  7. // Allow gene-based creatures to evolve within an environment.
  8. //
  9. // Features of this simulation include:
  10. // - gene-based control over characteristics
  11. // - mutation of genes at birth
  12. // - sexual and asexual reproduction
  13. // - creatures can be 100% herbivores... omnivores... 100% carnivores
  14. // - real-time display of entire ecosystem
  15. // - real-time display of statistics
  16. // - flexible control over ecosystem global variables
  17. // - AREXX interface
  18. //
  19. // History
  20. // -------
  21. // XX-AUG-92: Started this file.
  22. // 12-OCT-93: Added greyscales display option for crappy grey VGA monitor.
  23. // 02-JAN-94: Added Food vision capability to creatures.
  24. //
  25. //                           VERSION 1.2
  26. //
  27. // 13-MAR-94: Added a faster non-graphical (NOANIM) mode (using bytes for cells)
  28. //              + scenario settings now in variables instead of #defs.
  29. // 26-MAR-94: Changed code to use pointers to functions for CLI selectable
  30. //              non-animated (faster) mode.
  31. //              Added dying_age and moving speed genes. "BLIND" option.
  32. // 08-APR-94: Added sexuality... at last.
  33. // 10-APR-94: Started adding MenuStrip with dynamic statistics selection.
  34. // 12-APR-94: Finished Stats Menus.
  35. // 13-APR-94: Added Options Menu with Graph speeds as mutually excluding
  36. //            sub-items.
  37. // 16-APR-94: Added (non satisfactory) attempt to be NTSC-friendly.
  38. // 17-APR-94: Changed defaults to be NO SEX and NO VISION
  39. // 22-APR-94: Added checks for out-of-bounds global parameters on CMD line.
  40. // 27-APR-94: Added herbivore/carnivore capability
  41. // 01-MAY-94: Added my own AREXX compatibility, after thinking that the PD
  42. //            offerings were too complicated.
  43. // 03-MAY-94: Added rexxsyslib IsRexxMsg() sanity check for incoming msgs.
  44. //
  45. //                           VERSION 1.3
  46. //
  47. // 11-MAY-94: Changed Oasis food growth to true circular area.
  48. //              Killed some REXX bugs, created first REXX scenarios.
  49. // 12-MAY-94: Major gfx optimization: now using an interleaved bitmap for faster
  50. //              pixel routines.
  51. // 17-MAY-94: Made MAX_ENERGY a gene instead of a global constant.
  52. // 19-MAY-94: Forced screen Font to be Topaz 8*8
  53. //
  54. // TO DO
  55. // -----
  56. // - LOAD/SAVE entire state.
  57. // - Global parameters control panel
  58. // - Help menu
  59. // - long vertical hardware sprite as a crosshair type cursor over graphs.
  60. //
  61. // Lines marked **!! are potential bug sources.
  62. //
  63. // DESIGN MISTAKES:
  64. // ----------------
  65. // - When I added the NOANIM option and therefore the necessary parallel
  66. //   representation, I started a second path of development which had to
  67. //   have the same functionality as the original pixel-based system.
  68. //   This is bad: too much work maintaining the 2 systems.
  69. //   I should have used one single data structure capable of being displayed
  70. //   as pixels or not (as in NOANIM).
  71. //----------------------------------------------------------------------
  72.  
  73. #ifdef    DEBUG
  74. #define    ENTER(x)    printf("Entering..." x "\n");
  75. #define    LEAVE(x)    printf("Done    ..." x "\n\n");
  76. #endif
  77.  
  78. #define                    MONOCHROME    1            // running on a mono display!
  79.  
  80. //#define                FASTER        1            // enable to cut out IFAUDIT code...
  81.  
  82. // Major apology to the whole world out there: I am polishing this program on
  83. // a minimalistic grey-scale VGA monitor, so, sorry about the B&W look !
  84.  
  85. #include                <stdio.h>
  86. #include                <stdlib.h>
  87. #include                <string.h>
  88. #include                <math.h>
  89.  
  90. #ifdef    AMIGA
  91. #include                <exec/types.h>
  92. #include                <exec/execbase.h>
  93. #include                <exec/memory.h>
  94.  
  95. #include                <graphics/gfx.h>
  96.  
  97. #include                <intuition/intuitionbase.h>
  98. #include                <intuition/screens.h>
  99.  
  100. #include                <libraries/asl.h>
  101. #include                <libraries/gadtools.h>
  102.  
  103. #include                <utility/tagitem.h>
  104.  
  105. #include                <rexx/rxslib.h>                    // for AREXX Support !
  106. #include                <rexx/errors.h>
  107.  
  108. #include                <clib/exec_protos.h>            // ANSI function prototypes
  109. #include                <clib/alib_protos.h>
  110. #include                <clib/dos_protos.h>
  111. #include                <clib/graphics_protos.h>
  112. #include                <clib/intuition_protos.h>
  113. #include                <clib/gadtools_protos.h>
  114. #include                <clib/rexxsyslib_protos.h>
  115.  
  116. #define    LF                10
  117.  
  118. #else                                // if compiled on non-Amiga machines..
  119.  
  120. typedef    unsigned char    UBYTE;                    // 8 bits
  121. typedef    unsigned short    UWORD;                    // 16 bits
  122. typedef    unsigned long    ULONG;                    // 32 bits
  123.  
  124. #endif
  125.  
  126. typedef unsigned int    FLAG;                    // 32 bits **!! optimized for 68020+
  127. typedef unsigned int    RC;
  128.  
  129. //----------------------------------------------
  130. #define    CHAR_HEIGHT        8                        // Y size of Font.
  131.  
  132. #define    SCREEN_WIDTH    512                        // Screen dimension **!! FIXED
  133. #define    SCREEN_HEIGHT    512                        // HAS to be a power of 2.
  134. #define    ACRE            (SCREEN_WIDTH-1)        // POWER OF 2 **!! LEAVE AS IS
  135. #define    ECO_SCR_DEPTH    4                        // for 16 colors
  136.  
  137. #define    STATS_TOPY        12                        // offset from top of screen.
  138. #define    GRAPH_HEIGHT    64
  139. #define    STAT_SCR_WIDTH    640                        // Statistics Screen Width
  140. #define    STAT_SCR_DEPTH    3                        // only 8 colors needed.
  141.  
  142. #define    NUM_COLORS        (1<<ECO_SCR_DEPTH)
  143. #define    NUM_CELLS        (1<<ECO_SCR_DEPTH)
  144.  
  145. #define NEUT_CELL        0                        // has to be all 0s eg. %0000
  146. #define    VEGE_CELL        (NUM_CELLS-1)            // has to be all 1s eg. %1111
  147. #define    WALL_CELL        (NUM_CELLS-2)            // has to be all 1s eg. %1110
  148. #define    MAX_COLORS        (NUM_CELLS-3)
  149.  
  150. #define    SYNTAX_ERROR                (5)
  151. #define    FATAL_ERROR                    (20)
  152. #define    PROG_BUG_ERROR                (100)
  153.  
  154. #define    REXXERR_UNKNOWN_CMD            (10)
  155. #define    REXXERR_VAL_OUTSIDE_RANGE    (11)
  156.  
  157. //----------------------------------------------
  158. // Statistic Graphs constants
  159. //----------------------------------------------
  160.  
  161. #define    TIMER_SPEED        4                        // Time update speed
  162. #define    LE                (STAT_SCR_WIDTH-256)    // LABEL area for graphs
  163.  
  164. #define    NORMAL            0
  165. #define    FLIP_IT            1                        // don't change **!!
  166.  
  167. #define    CURGRAPH_Y        (STATS_TOPY+ graphnum*GRAPH_HEIGHT)    // current graph Y BASE
  168.  
  169. //-----------------------------
  170. // Main program data structures
  171. //-----------------------------
  172.  
  173. ULONG    time;                                // And God Createth Universal Time
  174. UWORD    runs=0;
  175. ULONG    daylight;                            // +100 to -100 (noon, midnight)
  176.  
  177. struct fast_pixel {
  178.     ULONG    pixel_byte_offs;                // offset of byte in plane
  179.     ULONG    pixel_bit_no;                    // minimal pixel info
  180. };
  181.  
  182.  
  183. // The BUG data structure is this program's core data structure, therefore
  184. // keep field positions optimized for a 32-bit data bus processor.
  185.  
  186. struct bug {
  187.  
  188.     FLAG    alive;                            // flag enabling all the other fields
  189.  
  190.                 // Individual time-dependent creature characteristics
  191.  
  192.     ULONG    age;                            // howmany timer ticks he's been around.
  193.     WORD    energy;                            // 0..procr_energy  (MAX +32767 **!!)
  194.     UWORD    x,y;                            // screen coords of bug.
  195.  
  196.     UWORD    generation;                        // which generation this guy is
  197.  
  198.     struct    fast_pixel prevpix;                // prev pixel info (for fast clear)
  199.  
  200.  
  201.     UBYTE    dir;                            // 0..7
  202.     UBYTE    speed_delay;                    // 0..3
  203.  
  204.                 // GENES (time-independent creature characteristics)
  205.  
  206.     UBYTE    right;                            // 0..255
  207.     UBYTE    left;                            //
  208.  
  209.     UBYTE    vision;                            // 0..255 scaled down to  ..
  210.     UBYTE    sexuality;                        // 0..255
  211.  
  212.     UBYTE    dirgene;                        //
  213.  
  214.     UBYTE    oxy_produce;
  215.     UBYTE    oxy_consume;
  216.     UBYTE    co2_produce;
  217.     UBYTE    co2_consume;
  218.  
  219.     UBYTE    dying_age;                        // 0..255 but scaled up to 0..65535
  220.  
  221.     UBYTE    maxsexage;                        // 0..255 but scaled up to 0..65535
  222.     UBYTE    minsexage;                        // 0..255 but scaled up to 0..4095
  223.  
  224.     UBYTE    speed;                            // 0..255 but scaled down in delay
  225.     UBYTE    foodtype;                        // 0..63 HERBI, 64..191 OMNI, 191..255 CARNI
  226.  
  227.     UBYTE    procr_energy;                    // procreate energy threshold 0..16384
  228.  
  229.     UBYTE dummy;
  230.     UWORD dummyw;
  231. };
  232.  
  233. struct bug dummy_bug;                        // one instance to pass as dummy arg.
  234.  
  235. typedef    UBYTE        CELL;                    // a cell in the 2-d array
  236. typedef struct bug    *BUGPTR;
  237.  
  238. // array holding MAX_BUGS simulated creatures (allocated at run-time)
  239.  
  240. BUGPTR bugs;                                // struct bug bugs[MAX_BUGS];
  241.  
  242. // To allow creatures to find out efficiently which "bug" structure is
  243. // connected to a particular creature pixel on-screen, we use a parallel
  244. // map to hold pointers to the "parent structures".
  245.  
  246. CELL    *environment;                    // ptr to BYTE-based env of creatures
  247. BUGPTR    *owner_ptrs;                    // ptr to parallel PARENTS map
  248. #define    PTR_MAP_SIZE    (sizeof(char *)*SCREEN_WIDTH*SCREEN_HEIGHT)
  249.  
  250. int color_divider;            // factor to map bug->energy to pixel pen number
  251.  
  252. //-----------------------------------------------------------
  253. // The following variables are counters for statistics/graphs
  254. //-----------------------------------------------------------
  255.  
  256. ULONG numbugs;
  257. ULONG food_in_system;
  258. ULONG births,deaths;
  259. ULONG total_energy;
  260. ULONG total_age;
  261. ULONG total_right, total_left, total_vision, total_dir;
  262. ULONG total_dying_age, total_minsexage, total_maxsexage;
  263. ULONG total_speed, total_sexuality;
  264. ULONG total_foodtype, total_procr;
  265.  
  266. ULONG total_O2, total_CO2;
  267.  
  268. UBYTE min_right,    max_right;
  269. UBYTE min_left,        max_left;
  270. UBYTE min_vision,    max_vision;
  271. UBYTE min_dying_age,max_dying_age;
  272. UBYTE min_speed,    max_speed;
  273. UBYTE min_sexuality,max_sexuality;
  274. UBYTE min_minsexage,max_minsexage;
  275. UBYTE min_maxsexage,max_maxsexage;
  276. UBYTE min_foodtype,    max_foodtype;
  277. UBYTE min_procr,    max_procr;
  278.  
  279. ULONG oxygen,carb_dioxide;
  280.  
  281. UBYTE stat_bufix=0;            // statistics buffer INDEX
  282.  
  283. struct statistic {
  284.     FLAG    displayed;        // currently displayed or not
  285.  
  286.     char    *label;            // Menu and Label string
  287.     ULONG    *stat_addr;        // ptr to statistic variable
  288.     UBYTE    *minmax_addr;    // -> minimum and maximum stats (if non-NULL)
  289.     ULONG    scale;            // maximum value equivalent to max scale
  290.     FLAG    flip_graph;        // normal or up-side-down graph ?
  291.     ULONG    *buffer;        // buffer[512] record circular buffer
  292. };
  293.  
  294. #define    NUM_STATS    (19)
  295.  
  296. struct statistic available_stats[] = {
  297.  { TRUE        ,"Number of Bugs....................."    ,&numbugs            ,NULL            ,34        ,NORMAL        ,0    },
  298.  { FALSE    ,"Number of Bug Births..............."    ,&births            ,NULL            ,64        ,NORMAL        ,0    },
  299.  { FALSE    ,"Number of Bug Deaths..............."    ,&deaths            ,NULL            ,64        ,NORMAL        ,0    },
  300.  { FALSE    ,"Average Bug Energy................."    ,&total_energy        ,NULL            ,32768    ,NORMAL        ,0    },
  301.  { FALSE    ,"Average Bug Age...................."    ,&total_age            ,NULL            ,65535    ,NORMAL        ,0    },
  302.  { TRUE        ,"Amount of food....................."    ,&food_in_system    ,NULL            ,5000    ,NORMAL        ,0    },
  303.  { TRUE        ,"Oscillator: Day/Night.............."    ,&daylight            ,NULL            ,100    ,NORMAL        ,0    },
  304.  { TRUE        ,"Gene Avg.: Clock-wise.............."    ,&total_right        ,&min_right        ,255    ,FLIP_IT    ,0    },
  305.  { TRUE        ,"Gene Avg.: Anti Clock-wise........."    ,&total_left        ,&min_left        ,255    ,FLIP_IT    ,0    },
  306.  { FALSE    ,"Gene Avg.: Vision.................."    ,&total_vision        ,&min_vision    ,255    ,NORMAL        ,0    },
  307.  { FALSE    ,"Gene Avg.: Sexuality..............."    ,&total_sexuality    ,&min_sexuality    ,255    ,NORMAL        ,0    },
  308.  { TRUE        ,"Gene Avg.: Lifespan................"    ,&total_dying_age    ,&min_dying_age    ,65535    ,NORMAL        ,0    },
  309.  { FALSE    ,"Gene Avg.: Min. Procreation Age...."    ,&total_minsexage    ,&min_minsexage    ,4096    ,NORMAL        ,0    },
  310.  { FALSE    ,"Gene Avg.: Min. Procreation Energy."    ,&total_procr        ,&min_procr        ,16384    ,NORMAL        ,0    },
  311.  { FALSE    ,"Gene Avg.: Max. Procreation Age...."    ,&total_maxsexage    ,&min_maxsexage    ,65535    ,NORMAL        ,0    },
  312.  { FALSE    ,"Gene Avg.: Moving Slowness........."    ,&total_speed        ,&min_speed        ,255    ,NORMAL        ,0    },
  313.  { TRUE        ,"Gene Avg.: Herbi-/Omni-/Carnivore.."    ,&total_foodtype    ,&min_foodtype    ,255    ,NORMAL        ,0    },
  314.  { FALSE    ,"Amount of Oxygen..................."    ,&total_O2            ,NULL            ,60000    ,NORMAL        ,0    },
  315.  { FALSE    ,"Amount of Carbon Dioxide..........."    ,&total_CO2            ,NULL            ,60000    ,NORMAL        ,0    },
  316.  
  317.  { 0        ,"**!! MENU BUG: GONE ONE TO FAR *."    ,NULL                ,NULL            ,0        ,0            ,0    }
  318. };
  319.  
  320. #define    EYE_ITEM    (9)
  321. #define    SEX_ITEM    (10)
  322. #define    OXY_ITEM    ( (sizeof(available_stats)/sizeof(struct statistic)) -3)
  323. #define    CO2_ITEM    ( (sizeof(available_stats)/sizeof(struct statistic)) -2)
  324.  
  325. UWORD graphnum;                                // current graph index
  326. UWORD graph_speed;                            // current graph update speed
  327. UWORD MAX_GRAPHS;                            // 6 or 8
  328. UWORD STAT_WIN_HEIGHT;
  329.  
  330. FLAG NUMERIC_STATS    = TRUE;
  331. FLAG MINMAX            = FALSE;                // draw minima/maxima too ?
  332.  
  333. //-------------------------------------------------------------------------
  334. // The following AmigaDOS-filled structure is used to store program globals.
  335. // The structure is initialized by DOS from the options the user passes
  336. // on the command line.
  337. // The program itself post-initializes any globals not set by the user.
  338. //-------------------------------------------------------------------------
  339.  
  340. struct RDAres {                                // array for ReadArgs()
  341.  
  342.     ULONG audit;                // report events on STDOUT ?
  343.     ULONG capture;                // save all stats to file ?
  344.     ULONG noanim;                // no animation of simulation ?
  345.     ULONG eyes;                    // enable vision gene ?
  346.     ULONG sex;                    // enable sexual pairing ?
  347.     ULONG showdefaults;
  348.     ULONG maxbugs;
  349.  
  350.     // Starting SCENARIO variables
  351.     // ---------------------------
  352.  
  353.     ULONG INIT_BUGS;
  354.     ULONG INIT_FOOD;
  355.     ULONG INIT_ENERGY;
  356.     ULONG INIT_VARIANCE;
  357. //    ULONG INIT_O2;
  358. //    ULONG INIT_CO2;
  359.  
  360.     ULONG MUTATE_RANGE;
  361.     ULONG FOOD_RATE;
  362.     ULONG FOOD_ENERGY;
  363.  
  364.     ULONG X_AND;
  365.     ULONG Y_AND;
  366.  
  367.     ULONG OASIS_SIZE;
  368.  
  369.     ULONG ntsc;                    // User supplies NTSC/PAL information !
  370.  
  371. } options;
  372.  
  373. #define    ASEXUAL            (FALSE)
  374. #define    SEXUAL            (TRUE)
  375.  
  376. #define    REPORT            (options.audit)
  377. #define    CAPTURE            (options.capture)
  378. #define    NOANIM            (options.noanim)
  379. #define    VISION            (options.eyes)
  380. #define    SEX                (options.sex)
  381. #define    SHOWDEFAULTS    (options.showdefaults)
  382. #define    MAX_BUGS        (options.maxbugs)
  383. #define    INIT_BUGS        (options.INIT_BUGS)
  384. #define    INIT_FOOD        (options.INIT_FOOD)
  385. #define    INIT_ENERGY        (options.INIT_ENERGY)
  386. #define    INIT_VARIANCE    (options.INIT_VARIANCE)
  387. //#define    INIT_O2            (options.INIT_O2)
  388. //#define    INIT_CO2        (options.INIT_CO2)
  389.  
  390. #define    MUTATE_RANGE    (options.MUTATE_RANGE)
  391. #define    FOOD_RATE        (options.FOOD_RATE)
  392. #define    FOOD_ENERGY        (options.FOOD_ENERGY)
  393. #define    X_AND            (options.X_AND)
  394. #define    Y_AND            (options.Y_AND)
  395. #define    OASIS_SIZE        (options.OASIS_SIZE)
  396. #define    NTSC            (options.ntsc)
  397.  
  398. #define    IFAUDIT        if (REPORT)
  399.  
  400. #ifdef AMIGA
  401.  
  402. char MJIT_DOS_TEMPLATE[] =
  403.  
  404. "AUDIT/S,DATALOG/S,NOANIM/S,VISION/S,SEX/S,SHOWDEFAULTS/S,MAX_BUGS/K,\
  405. INIT_BUGS/K,INIT_FOOD/K,INIT_ENERGY/K,INIT_VARIANCE/K,MUTATE_RANGE/K,\
  406. FOOD_RATE/K,FOOD_ENERGY/K,X_AND/K,Y_AND/K,\
  407. OASIS_SIZE/K,NTSC/S";
  408. #endif
  409.  
  410. // The Variable structure defines program globals which can be accessed or
  411. // changed via the command line and/or the AREXX interface.
  412.  
  413. struct variable {
  414.     UBYTE    flags;            // global and/or init
  415.  
  416.     char    *name;            // name of a global parameter
  417.     ULONG    *address;        // its address
  418.  
  419.     ULONG    init_val;        // initial default value
  420.     ULONG    min_val;        // range minimum
  421.     ULONG    max_val;        // range maximum
  422. };
  423.  
  424. #define    PARAMETER    1
  425.  
  426. struct variable varlist[] = {
  427.     {0            ,"MAX_BUGS"        ,&MAX_BUGS        ,300    ,20        ,1000    },
  428.     {PARAMETER    ,"INIT_BUGS"    ,&INIT_BUGS        ,44        ,1        ,100    },
  429.     {PARAMETER    ,"INIT_FOOD"    ,&INIT_FOOD        ,3189    ,1        ,30000    },
  430.     {PARAMETER    ,"INIT_ENERGY"    ,&INIT_ENERGY    ,624    ,10        ,15000    },
  431.     {PARAMETER    ,"INIT_VARIANCE",&INIT_VARIANCE    ,182    ,1        ,250    },
  432. //    {0            ,"INIT_O2"        ,&INIT_O2        ,32000    ,1        ,100000    },
  433. //    {0            ,"INIT_CO2"        ,&INIT_CO2        ,4000    ,1        ,100000    },
  434.  
  435.     {PARAMETER    ,"MUTATE_RANGE"    ,&MUTATE_RANGE    ,48        ,1        ,120    },
  436.     {PARAMETER    ,"FOOD_RATE"    ,&FOOD_RATE        ,10        ,1        ,100    },
  437.     {PARAMETER    ,"FOOD_ENERGY"    ,&FOOD_ENERGY    ,624    ,1        ,5000    },
  438.     {PARAMETER    ,"X_AND"        ,&X_AND            ,1        ,1        ,260    },
  439.     {PARAMETER    ,"Y_AND"        ,&Y_AND            ,1        ,1        ,260    },
  440.     {PARAMETER    ,"OASIS_SIZE"    ,&OASIS_SIZE    ,0        ,0        ,50        },
  441.  
  442.     {NULL        ,NULL            ,NULL            ,NULL    ,0        ,0        }
  443. };
  444.  
  445. // The Command structure array defines commands which AREXX can issue us.
  446.  
  447. struct command {
  448.     UBYTE    flags;
  449.  
  450.     char    *name;                            // name of a REXX command
  451.     RC        (*address)(void *);                // function's address
  452. };
  453.  
  454. RC    please_quit        (void *);    // some forward declarations
  455. RC    restart            (void *);
  456. RC    enable_sex         (void *);
  457. RC    disable_sex        (void *);
  458. RC    enable_vision    (void *);
  459. RC    disable_vision    (void *);
  460. RC    return_bugs        (void *);
  461. RC    return_runs        (void *);
  462. RC    return_timesteps(void *);
  463. RC    dumpdefaults    (void *);
  464.  
  465. struct command cmdlist[] = {
  466.     {0    ,"MJ_QUIT"            ,&please_quit        },
  467.     {0    ,"MJ_RESET"            ,&restart            },
  468.     {0    ,"MJ_DUMPDEFAULTS"    ,&dumpdefaults        },
  469.  
  470.     {0    ,"MJ_SEX"            ,&enable_sex        },
  471.     {0    ,"MJ_NOSEX"            ,&disable_sex        },
  472.     {0    ,"MJ_VISION"        ,&enable_vision        },
  473.     {0    ,"MJ_NOVISION"        ,&disable_vision    },
  474.  
  475.     {0    ,"MJ_BUGS?"            ,&return_bugs        },
  476.     {0    ,"MJ_RUNS?"            ,&return_runs        },
  477.     {0    ,"MJ_TIMESTEPS?"    ,&return_timesteps    },
  478.  
  479.     {0    ,0                    ,0                    }
  480. };
  481.  
  482. //-------------------------------------------------------------------------
  483.  
  484. struct move_vec {
  485.     short dx;            // a vector describing a direction or move.
  486.     short dy;
  487. };
  488.  
  489.  
  490. #define    NUM_NEIGHBORS        8                // as on a chess board.
  491.  
  492. // direction vectors for the 8 directions
  493.  
  494. struct move_vec xymovs[NUM_NEIGHBORS] =    {
  495.     {1,0},
  496.     {1,1},
  497.     {0,1},
  498.     {-1,1},
  499.     {-1,0},
  500.     {-1,-1},
  501.     {0,-1},
  502.     {1,-1}
  503. };
  504.  
  505. int    nbor_offs[NUM_NEIGHBORS] = {
  506.     -1,        1,
  507.     -512, 512,
  508.     -513, 511,
  509.     -511, 513
  510. };
  511.  
  512. // exponentially decreasing "scent" weights according to distance
  513.  
  514. UBYTE scent_vals[]=
  515.     {    254    ,253    ,252    ,251    ,
  516.         250    ,250    ,250    ,250    ,
  517.         249    ,249    ,249    ,249    ,
  518.         248    ,248    ,247    ,247    ,
  519.         246    ,245    ,244    ,243    ,
  520.         242    ,240    ,240    ,240    ,
  521.         235    ,235    ,230    ,230    ,    // for vision beyond 32    , code will index
  522.         230    ,210    ,200    ,100};        // beyond this point **!!
  523.  
  524. char    strbuf[80];                // generic string buffer
  525. char    linebuf[512];            // CAPTURE line buffer
  526. char    *lineptr;                // ptr into above
  527.  
  528. FLAG    quit_me;                // request to terminate program
  529. FLAG    auto_reset;                // reset ecosys when bugs=0
  530. UWORD    food_timer;                // timer for feeding time.
  531. UWORD    sim_speed;                // slow-motion or no delay ?
  532.  
  533. //-------------------------------------------------------------------------
  534. #ifdef    AMIGA
  535.  
  536. extern    struct ExecBase        *SysBase;            // basic Kernel services
  537. extern    struct GfxBase        *GfxBase;            // low-level graphics
  538. extern    struct IntuitionBase *IntuitionBase;    // WIMP interface
  539.         struct Library        *RexxSysBase;        // AREXX support
  540.  
  541. //-------------------------------------------------------------------------
  542. // A NewScreen struct to open application Screens.
  543. //-------------------------------------------------------------------------
  544.  
  545. struct NewScreen ns = { 0,0, 640, 400, 2,
  546.                         0,1,HIRES|LACE,0,
  547.                         NULL,
  548. "MegaJITTER V1.3 Statistics                        (c) 1992-1994 L.Vanhelsuwé",
  549.                         NULL,NULL};
  550.  
  551. char scr_name[]="MegaJITTER Ecology Simulator";
  552.  
  553. struct TextAttr txtattr = {
  554.     "topaz.font", 8, 0,0
  555. };
  556.  
  557. struct    RastPort    *stat_rp;
  558. struct    BitMap        *bm;            // allocated via AllocBitMap()
  559.  
  560. struct    Screen        *eco_screen,*stat_screen;
  561. struct    Window        *window;
  562. struct    Menu        *menustrip = 0;
  563. void    *vi;                                // global VisualInfo ptr for Workbench Screen
  564.  
  565. ULONG    *plane0;                            // ASM routines access this **!!
  566.  
  567. char    version[]="$VER: MegaJitter 1.3 ©LVA 06/MAY/94";
  568.  
  569. #define    REXXPORTNAME    "REXX-MJ"
  570. //-------------------------------------------------------------------------
  571. // A NewWindow struct to open application Windows.
  572. //-------------------------------------------------------------------------
  573.  
  574. struct NewWindow nw = {
  575.     0, STATS_TOPY,
  576.     STAT_SCR_WIDTH, 200,
  577.     255, 255,                            /* Default pens */
  578.  
  579.             // I want to know about following IDCMP Message types
  580.     IDCMP_MENUPICK,
  581.  
  582.             // INVISIBLE window flags
  583.     WFLG_BORDERLESS | WFLG_ACTIVATE,
  584.  
  585.     NULL,                                // No gadgets in this window
  586.  
  587.     (struct Image *) NULL,
  588.  
  589.     (char *)         NULL,                // Window title
  590.  
  591.     (struct Screen *) NULL,                // to be filled in.
  592.  
  593.     (struct BitMap *) NULL,
  594.  
  595.     0, 0,                                /* Minimum sizes */
  596.     65535, 65535,                        /* Maximum sizes */
  597.     CUSTOMSCREEN                        /* and put it IN our screen */
  598. };
  599.  
  600. //-------------------------------------------------------------------------
  601. // Menu Layout in compact GadTools format.
  602. //
  603. // **!! NOTE Mutual exclusion masks for Graph speed subitems !
  604. //-------------------------------------------------------------------------
  605.  
  606. #define    PROJECT_MENU        0
  607. #define    OPTIONS_MENU        1
  608. #define    STATS_MENU            2
  609. #define    HELP_MENU            3
  610.  
  611. #define     PROJ_MENU_RESET    0
  612. #define     PROJ_MENU_LOAD        1
  613. #define     PROJ_MENU_SAVE        2
  614. #define    DUMMY_ITEM0            3
  615. #define     PROJ_MENU_ABOUT    4
  616. #define     PROJ_MENU_AUTHOR    5
  617. #define     PROJ_MENU_QUIT        6
  618.  
  619. #define    OPT_MENU_CTRL_PANEL    0
  620. #define    OPT_MENU_SIM_SPEED    1
  621. #define    OPT_MENU_STAT_SPEED    2
  622. #define    OPT_MENU_RESET        3
  623. #define    OPT_MENU_AUDIT        4
  624. #define    OPT_MENU_MINMAX        5
  625.  
  626. #define    HELP_MENU_a            0
  627. #define    HELP_MENU_b            1
  628.  
  629. // First empty slot for list of statistics at offset N
  630.  
  631. #define    NEWMENU_AUDIT    22
  632. #define    NEWMENU_APPEND    25
  633.  
  634. struct NewMenu mymenus[NUM_STATS+NEWMENU_APPEND+2]= {    // +END_MARKER + SAFETY
  635.  
  636. { NM_TITLE,    "Project"                ,0        ,0                        ,0        ,0},
  637. { NM_ITEM,      "Reset"                ,"N"    ,0                        ,0        ,0},    // Big Bang !
  638. { NM_ITEM,      "Load..."                ,"L"    ,0                        ,0        ,0},    // Load
  639. { NM_ITEM,      "Save..."                ,"S"    ,0                        ,0        ,0},    // Save
  640. { NM_ITEM,       NM_BARLABEL            ,0        ,0                        ,0        ,0},
  641. { NM_ITEM,      "About.."                ,"?"    ,0                        ,0        ,0},
  642. { NM_ITEM,      "Author..."            ,0        ,0                        ,0        ,0},
  643. { NM_ITEM,      "Quit"                ,"Q"    ,0                        ,0        ,0},
  644.  
  645. { NM_TITLE,    "Control"                ,0        ,0                        ,0        ,0},
  646. { NM_ITEM,     "Global Parameters..."    ,0        ,0                        ,0        ,0},
  647. { NM_ITEM,      "Simulation Speed"    ,0        ,0                        ,0        ,0},
  648. { NM_SUB,        "Full Speed"        ,"F",CHECKED|CHECKIT|MENUTOGGLE ,0x02    ,0},
  649. { NM_SUB,        "Slow-Motion"        ,"Z",         CHECKIT|MENUTOGGLE ,0x01    ,0},
  650. { NM_ITEM,      "Statistics Speed"    ,0        ,0                        ,0        ,0},
  651. { NM_SUB,        "Ultra Slow"        ,"1",         CHECKIT|MENUTOGGLE    ,0x7E    ,0},
  652. { NM_SUB,        "Very Slow"            ,"2",         CHECKIT|MENUTOGGLE    ,0x7D    ,0},
  653. { NM_SUB,        "Slow"                ,"3",         CHECKIT|MENUTOGGLE    ,0x7B    ,0},
  654. { NM_SUB,        "Normal"            ,"4",CHECKED|CHECKIT|MENUTOGGLE    ,0x77    ,0},
  655. { NM_SUB,        "Fast"                ,"5",         CHECKIT|MENUTOGGLE    ,0x6F    ,0},
  656. { NM_SUB,        "Very Fast"            ,"6",         CHECKIT|MENUTOGGLE    ,0x5F    ,0},
  657. { NM_SUB,        "Ultra Fast"        ,"7",         CHECKIT|MENUTOGGLE    ,0x3F    ,0},
  658. { NM_ITEM,      "Reset on Extinction"    ,"R",CHECKED|CHECKIT|MENUTOGGLE    ,0        ,0},
  659. { NM_ITEM,      "Toggle Audit Trail"    ,"A",         CHECKIT|MENUTOGGLE    ,0        ,0},
  660. { NM_ITEM,      "Toggle Minima/Maxima","M",         CHECKIT|MENUTOGGLE    ,0        ,0},
  661.  
  662. { NM_TITLE,    "Statistics"            ,0        ,0                        ,0      ,0}
  663.     // Here we dynamically append the statistics menu items...
  664. };
  665.  
  666. BPTR    capture_file;                            // **!! not used
  667.  
  668. struct MsgPort *rexx_port;
  669.  
  670. #endif        // AMIGA OS specific structs
  671.  
  672. //-------------------------------------------------------------------------
  673. // ---------------------------
  674. // Now the function prototypes
  675. // ---------------------------
  676.  
  677. void    handle_bug                    (BUGPTR creat);
  678. void    spawn_child                    (BUGPTR mother, BUGPTR father, FLAG sexy);
  679. void    grow_food                    (void);
  680.  
  681. void    open_libraries                (void);
  682. void    init_defaults                (struct variable *varptr);
  683. void    init_gfx                    (void);
  684. void    alloc_structs                (void);
  685.  
  686. void    close_ecosys                (void);
  687. void    close_gfx                    (void);
  688. void    wipe_environment            (void);
  689. FLAG    reset_ecosystem                (void);
  690.  
  691. void    reset_global_stats            (void);
  692. void    collect_bug_stats            (BUGPTR creat);
  693. void    update_statistics            (void);
  694. void    print_stat                    (struct statistic *stat, ULONG num, int x);
  695. void    print_minmax                (struct statistic *stat, UBYTE value, int x);
  696.  
  697. void    append_stats_menus            (void);
  698. void    toggle_stat                    (void);
  699. void    handle_IDCMP_msgs            (void);
  700. void    handle_AREXX_msgs            (void);
  701. void    handle_menuselection        (SHORT menu);
  702. void    uncheck_menuitem            (int menunum, int itemnum);
  703. void    popup_About_req                (void);
  704. void    popup_Author_req            (void);
  705. void    PaintStatLabels                (void);
  706. void    PaintStatValues                (void);
  707. void    RePaintGraphs                (void);
  708. void    WriteString                    (UWORD x, UWORD y, char *string);
  709. void    close_REXX                    (void);
  710.  
  711. FLAG    kill_switch                    (void);
  712. FLAG    get_user_options            (void);
  713. FLAG    menuitem_checkstate            (int menunum, int itemnum);
  714. FLAG    post_REXX_port                (char * portname);
  715. RC        parse_rexx_cmd                (struct RexxMsg* msg);
  716.  
  717. UBYTE    mutate                        (UBYTE gene);
  718. UBYTE    mix                            (UBYTE gene1, UBYTE gene2);
  719.  
  720. int        quick_req                    (char *message, char *exit);
  721. short    rnd                            (void);
  722.  
  723. // The program has two fundamentally different ways of doing things:
  724. // 1) It uses colored pixels in a visible screen to store the ecosystem.
  725. // 2) It uses an invisible BYTE-map to hold the ecosystem.
  726. //
  727. // The program itself is unaware of this difference by using function pointers
  728. // to 2 sets of routines doing the same thing, but on 2 different representations.
  729.  
  730. void    (*cell_writer)                (ULONG x, ULONG y, ULONG cell, BUGPTR bug);
  731. void    (*cell_eraser)                (BUGPTR bug);
  732. CELL    (*cell_typer)                (ULONG x, ULONG y);
  733. FLAG    (*food_checker)                (ULONG x, ULONG y);
  734. FLAG    (*clear_checker)            (ULONG x, ULONG y);
  735.  
  736. #define    set_cell_to(x,y,cell,bug)    (*cell_writer)    ((x),(y),(cell),(bug))
  737. #define    erase_cell(bug)                (*cell_eraser)    (bug)
  738. #define    cell_type(x,y)                (*cell_typer)    ((x),(y))
  739. #define    is_food(x,y)                (*food_checker)    ((x),(y))
  740. #define    is_empty(x,y)                (*clear_checker)((x),(y))
  741.  
  742. void        blind_put_cell            (ULONG x, ULONG y, ULONG cell, BUGPTR bug);
  743. void        gfx_put_cell            (ULONG x, ULONG y, ULONG cell, BUGPTR bug);
  744. extern void    asm_plot_pixel            (struct fast_pixel *fp, ULONG x, ULONG y, UBYTE color);
  745.  
  746. void        blind_wipe_cell            (BUGPTR bug);
  747. void        gfx_wipe_cell            (BUGPTR bug);
  748. extern void    asm_fastwipe_pixel        (struct fast_pixel *fp);
  749.  
  750. CELL        blind_cell_type            (ULONG x, ULONG y);
  751. extern CELL    asm_read_pixel            (ULONG x, ULONG y);
  752.  
  753. FLAG        blind_is_food            (ULONG x, ULONG y);
  754. extern FLAG    asm_is_food                (ULONG x, ULONG y);
  755.  
  756. FLAG        blind_is_empty            (ULONG x, ULONG y);
  757. extern FLAG    asm_is_empty            (ULONG x, ULONG y);
  758.  
  759. //============================================================================
  760. //
  761. //    MAIN()
  762. //
  763. // The main loop consists of:
  764. //
  765. //  - resetting per-loop statistics
  766. //  - letting all live creatures do their thing once (& accumulating stats)
  767. //  - now and again dropping some food.
  768. //  - now and again updating the scrolling graphs with simualtion statistics
  769. //
  770. //============================================================================
  771.  
  772. void main(int argc, char **argv) {
  773.  
  774. UWORD i;
  775. BUGPTR creat;                    // pointer to current creature
  776.  
  777.     if (sizeof(struct bug) & 3)
  778.         printf("Warning : Bug Structure is not LONG-word-multiple sized (sizeof: %d)\n", sizeof(struct bug));
  779.  
  780. // This program needs at least OS version 2.0 and a Motorola 68020 CPU.
  781.  
  782.     if ( ((struct Library*)SysBase)->lib_Version < 39) {
  783.         printf("I'm very sorry, but this program needs at least OS V39.\n");
  784.         exit(FATAL_ERROR);
  785.     }
  786.  
  787.     if ( (SysBase->AttnFlags & AFF_68020) == 0 ) {
  788.         printf("I'm very sorry, but this program needs at least a 68020 CPU.\n");
  789.         exit(FATAL_ERROR);
  790.     }
  791.  
  792.     printf("MegaJitter V1.3 (C) 1992-94 Laurence Vanhelsuwé.\n");
  793.     printf("An Evolution Simulator.\n\n");
  794.  
  795.     if (FindPort(REXXPORTNAME)) {
  796.         printf("MegaJitter is already running!\n\n");
  797.         printf("You can control the running program by executing AREXX scripts which\n");
  798.         printf("communicate with MJ through the \"ADDRESS '" REXXPORTNAME "'\" command.\n");
  799.         exit(FATAL_ERROR);
  800.     }
  801.  
  802. // Grab Intuition, Graphics, REXX, ... function libraries.
  803.  
  804.     open_libraries();
  805.  
  806.     if (get_user_options()) {    // ARGUMENT PARSING done Amiga-specific !
  807.  
  808.         printf("Error in user selected options. Please consult documentation.\n");
  809.  
  810.         close_gfx();        
  811.         exit(FATAL_ERROR);
  812.     }
  813.  
  814.     if (!post_REXX_port(REXXPORTNAME)) {        // create public REXX (input) port
  815.         printf("Couldn't open AREXX communications port!\n");
  816.  
  817.         close_gfx();        
  818.         exit(FATAL_ERROR);
  819.     }
  820.  
  821.     init_gfx();                                    // init graphics-related stuff.
  822.  
  823.     alloc_structs();                            // allocate data structs
  824.  
  825.     reset_ecosystem();                            // init eco data structs
  826.  
  827.     SetTaskPri(FindTask(0L), -5);        // lower our priority: be user friendly
  828.  
  829.     births = deaths = 0;                        // update_stats resets
  830.  
  831.     while ( !kill_switch() ) {                    // JOYSTICK FIRE BUTTON ends !!
  832.  
  833.         if (sim_speed) Delay(sim_speed);        // slow-motion or not ?
  834.  
  835.         IFAUDIT printf("T = %5d\n", time);
  836.  
  837.         time++;                                    // time flows in Universe..
  838.  
  839.         reset_global_stats();                    // reset some statistics counters
  840.  
  841.             // modulate daylight using time counter.
  842.         daylight = 50+ (WORD) (50 * cos( ((double)time) / 4000 ) );
  843.  
  844.             //----------------------------------------------------------------
  845.             // Process all creatures... let them live.
  846.             //----------------------------------------------------------------
  847.  
  848.         creat = &bugs[0];                        // -> 1st bug in ecosystem
  849.         for (i=0; i< MAX_BUGS; i++, creat++) {    // scan array for living bugs
  850.             if (creat->alive) {
  851.                 handle_bug(creat);                // let creature do its things
  852.             }
  853.         }
  854.  
  855.             //----------------------------------------------------------------
  856.             // Now collect some statistics from all live bugs..
  857.             //----------------------------------------------------------------
  858.  
  859.         numbugs    = 0;
  860.         creat = &bugs[0];                        // -> 1st bug in ecosystem
  861.         for (i=0; i< MAX_BUGS; i++, creat++) {    // scan array for living bugs
  862.             if (creat->alive) {
  863.                 numbugs++;
  864.                 collect_bug_stats(creat);        // then collect some figures..
  865.             }
  866.         }
  867.             //----------------------------------------------------------------
  868.             // If everything died and auto_reset feature is ON: restart all.
  869.             //----------------------------------------------------------------
  870.  
  871.         if (!numbugs && auto_reset) reset_ecosystem();
  872.  
  873.             //----------------------------------------------------------------
  874.             // Generate food for creatures.
  875.             //----------------------------------------------------------------
  876.  
  877.         if (food_timer--) {}
  878.         else {
  879.             food_timer = FOOD_RATE;                // reset counter.
  880.             grow_food();                        // and drop a parcel of manna.
  881.             grow_food();                        // twice
  882.         }
  883.  
  884.         update_statistics();                    // update stats graphs
  885.  
  886.         handle_IDCMP_msgs();                    // check our external events...
  887.  
  888.         if (RexxSysBase) handle_AREXX_msgs();    // check rexx Msgs only if REXX active
  889.  
  890.     }    // END OF MAIN LOOP
  891.  
  892.  
  893. // God pressed fire button on joystick: kill off Universe !
  894.  
  895.     close_ecosys();                                // dealloc data structs
  896.     close_gfx();                                // close screens.
  897.     close_REXX();
  898.     SetTaskPri(FindTask(0L), 0);        // restore standard CLI priority
  899.  
  900.     exit(0);                            // don't set any return code
  901. }
  902. //===============================================================
  903. //                      CREATURE ROUTINE
  904. //                        ----------------
  905. // This routine is called for every live creature.
  906. // It does some things unconditionally to all creatures like
  907. //    - ageing
  908. //    - exhausting
  909. //
  910. // and does other things in a gene-dependent way like
  911. //    - moving
  912. //    - seeing
  913. //    - reproducing
  914. //    - dying of old age
  915. //
  916. //===============================================================
  917.  
  918. void handle_bug (BUGPTR creat) {
  919.  
  920. UBYTE ran, rot, color;
  921. register int offs, x,y, dx,dy, coordmask;
  922. int vision,scent,distance, hurdle;
  923. short i;
  924. CELL cell;
  925. BUGPTR *sexy,*neighb, partner;            // ptr to bugs wanting sex.
  926. BUGPTR victim;
  927.  
  928.     creat->age++;                        // creatures age in sync with Time...
  929.     creat->energy--;                    // energy is constantly going down
  930.  
  931. #ifndef FASTER
  932.     IFAUDIT if (creat->energy < 100)
  933.             printf("Bug #%3d is dying of exhaustion (E: %d)\n", creat-bugs, creat->energy);
  934. #endif
  935.  
  936. // If creature exhausts energy or its designed lifespan... it dies.
  937.  
  938.     if (creat->energy    <= 0) {
  939.  
  940.         creat->alive = FALSE;
  941.         erase_cell(creat);                // then creature dies...
  942.         deaths++;                        // track morbidity rate
  943. #ifndef FASTER
  944.         IFAUDIT printf("Bug #%3d died of lack of energy.\n", creat-bugs);
  945. #endif
  946.  
  947.         return;
  948.  
  949.     } else
  950.  
  951. // If creature beyond optimum life span, start throwing dice but bias survival
  952. // with age overrun and creatures' energy (the fittest have a better chance).
  953.  
  954.     if (creat->age        >= (creat->dying_age <<8 )) {
  955.  
  956. #ifndef FASTER
  957.         IFAUDIT printf("Bug #%3d is dying of old age (AGE: %d > %d)", creat-bugs, creat->age, creat->dying_age<<8);
  958. #endif
  959.  
  960.         hurdle = creat->age - (creat->dying_age <<8);    // negative bias
  961.         hurdle -= creat->energy;                        // positive bias
  962.         if (hurdle < 0) hurdle = 0;
  963.  
  964.         if (( rnd() & 0x1FFF) < hurdle) {    // dice value upto 8191
  965.  
  966.             creat->alive = FALSE;
  967. #ifndef FASTER
  968.             IFAUDIT printf("Died of old age (ENERGY: %d).\n", creat->energy);
  969. #endif
  970.             erase_cell(creat);                // then creature dies...
  971.             deaths++;                        // track morbidity rate
  972.             return;
  973.  
  974.         } 
  975. #ifndef FASTER
  976.         else
  977.             IFAUDIT printf("But is hanging on... (ENERGY: %d).\n", creat->energy);
  978. #endif
  979.     }
  980.  
  981. // Control speed of each creature.
  982.  
  983.     if (creat->speed_delay >= 1) {        // while speed delay counter ticks...
  984.         creat->speed_delay--;            // don't move.
  985.         return;
  986.     }
  987.     creat->speed_delay = creat->speed >> 5;    //    0..7
  988.  
  989. // At this point, our creature decides it's gonna move.
  990. // This entails an energy penalty.
  991.  
  992.     creat->energy -= 2;                    // moving is N times harder than not moving
  993.  
  994. // Check energy exhaustion again.
  995.  
  996.     if (creat->energy    <= 0) {
  997.         creat->alive = FALSE;
  998. #ifndef FASTER
  999.         IFAUDIT printf("Bug #%3d died of lack of energy when moving.\n", creat-bugs);
  1000. #endif
  1001.  
  1002.         erase_cell(creat);                // then creature dies...
  1003.         deaths++;                        // track morbidity rate
  1004.         return;
  1005.     }
  1006.  
  1007. // Here's the engine of biological Evolution: when a creature reaches a certain
  1008. // level of fitness, it wants to procreate.
  1009. // Procreation occurs in two modes:
  1010. //
  1011. // 1) ASEXUAL:    it just "splits". The child creature is slightly mutated.
  1012. // 2) SEXUAL: the creature looks for a neighbor who's also "sex-ripe"
  1013. //
  1014. // This is the mechanism that allows stronger (and weaker) forms to emerge.
  1015. // The environment will determine the statistical chances of survival and thus
  1016. // the path of evolution and extinctions.
  1017.  
  1018.     if (creat->energy > creat->procr_energy<<6 ) {
  1019.  
  1020. #ifndef FASTER
  1021.         IFAUDIT printf("Bug #%3d Needs to procreate (E=%4d > %4d)\t", creat-bugs, creat->energy, creat->procr_energy<<6);
  1022. #endif
  1023.  
  1024.         if (creat->age < (creat->minsexage<<4)) {
  1025. #ifndef FASTER
  1026.             IFAUDIT printf("But is too young...(AGE: %d < %d)\n", creat->age, creat->minsexage<<4);
  1027. #endif
  1028.         } else
  1029.  
  1030.         if (creat->age > (creat->maxsexage<<8)) {
  1031. #ifndef FASTER
  1032.             IFAUDIT printf("But is too old...(AGE: %d > %d)\n", creat->age, creat->maxsexage<<8);
  1033. #endif
  1034.         } else
  1035.  
  1036.         if (!SEX) {
  1037. #ifndef FASTER
  1038.             IFAUDIT printf("Just splitting...\n");
  1039. #endif
  1040.             spawn_child(creat, (BUGPTR) 0, ASEXUAL);
  1041.         } else
  1042.  
  1043.         if ( (UBYTE)rnd() < creat->sexuality ) {
  1044. #ifndef FASTER
  1045.             IFAUDIT printf("Looking for mate...");
  1046. #endif
  1047.             sexy = owner_ptrs + creat->x + (creat->y <<9);
  1048.  
  1049.         // Check all around randy bug to see if there's another bug with
  1050.         // which it can mate.
  1051.  
  1052.             for(i=0; i<NUM_NEIGHBORS; i++) {
  1053.  
  1054.                 offs = nbor_offs[i];
  1055.  
  1056.                     // Make sure we don't index into out-of-bounds RAM
  1057.                     // This could occur at the very top or the very bottom of
  1058.                     // the array, optionally we could AND **!!
  1059.  
  1060.                 if (offs > 0 ) {
  1061.                     if (creat->y == ACRE) continue;
  1062.                 } else {
  1063.                     if (creat->y == 0) continue;
  1064.                 }
  1065.  
  1066.                 neighb = sexy + offs;
  1067.  
  1068.                 if (partner = *neighb) {
  1069.                     
  1070.                     if (partner < bugs || partner > &bugs[MAX_BUGS]) {
  1071.                         printf("FATAL BUG: owner_ptr (%08X) doesn't point back to a creature !!\n", partner);
  1072.                         printf("Mother #%d (x,y)= (%d,%d)\n", creat-bugs, creat->x, creat->y);
  1073.                         printf("Trying to mate with offset %d (%d)\n", i, nbor_offs[i]);
  1074.                         exit(PROG_BUG_ERROR);
  1075.                     }
  1076.  
  1077. #ifndef FASTER
  1078.                     IFAUDIT printf("\nPartner found @ (%d,%d)\n", partner->x, partner->y);
  1079. #endif
  1080.  
  1081.                     // Select partners which are strong and healthy !!
  1082.  
  1083.                     if (partner->energy > creat->energy) {
  1084.  
  1085. #ifndef FASTER
  1086.                         IFAUDIT {
  1087.                             printf("Sex ! (BUGS: %d & %d, ENERGIES: %d & %d)\n", creat-bugs, partner-bugs, creat->energy, partner->energy);
  1088.  
  1089.                             printf("Mother (x,y)= (%d,%d)\n", creat->x, creat->y);
  1090.                             printf("Father (x,y)= (%d,%d)\n", partner->x, partner->y);
  1091.                         }
  1092. #endif
  1093.                         spawn_child(creat, partner, SEXUAL);
  1094.                         break;
  1095.  
  1096.                     } else IFAUDIT printf("Partner to weak ! (%d < %d)\n", partner->energy, creat->energy);
  1097.                 }
  1098.             }
  1099.  
  1100.             IFAUDIT if (i==NUM_NEIGHBORS) printf("Failed to locate.\n");
  1101.  
  1102.         } else {
  1103. #ifndef FASTER
  1104.             IFAUDIT printf("Just splitting...\n");
  1105. #endif
  1106.             spawn_child(creat, (BUGPTR) 0, ASEXUAL);
  1107.         }
  1108.     }        // IF ENERGY > PROCR_ENERGY
  1109.  
  1110.  
  1111. // This section implements food vision (if not disabled)
  1112. // A creature's vision gets modulated by the time of day.
  1113. //  0.. 25 = total darkness (blind)
  1114. // 25..100 = 0..100% vision.
  1115.  
  1116.     scent        = 0;                    // accumulated scent = 0
  1117.  
  1118.     if (VISION) {
  1119.         if (daylight > 25) {            // if it's day ... (night = total dark)
  1120.  
  1121.             vision        = creat->vision>>2;        // shrink 0..255 gene to 0..63 length range
  1122.  
  1123.             i = vision    = (int) ((float) vision * (float) (daylight-25) / 75.0);
  1124.  
  1125.             distance    = 0;                    // set distance index to 0
  1126.  
  1127.             dx            = xymovs[creat->dir].dx;    // look in direction of
  1128.             dy            = xymovs[creat->dir].dy;    // current movement.
  1129.  
  1130.             coordmask    = ACRE;                    // cache andmask 511 in register
  1131.  
  1132.             x            = (creat->x +dx) & ACRE;
  1133.             y            = (creat->y +dy) & ACRE;
  1134.  
  1135.             while(i--) {
  1136.                 if ( ! is_empty(x, y))
  1137.                     scent += scent_vals[distance];
  1138.  
  1139.                 x = (x+dx) & coordmask;        // & ACRE to ensure we don't look
  1140.                 y = (y+dy) & coordmask;        // beyond world boundary **!!
  1141.                 distance++;
  1142.             }
  1143.  
  1144. #ifndef FASTER
  1145.             IFAUDIT if (scent) printf("Bug #%3d detected food with a vision of %3d (scent: %d)\n", creat-bugs, vision, scent);
  1146. #endif
  1147.         }
  1148.     }
  1149.  
  1150. // This section of code determines how creatures move.
  1151. // The strength of the scent LOWERS the probability of doing a gene-induced turn
  1152.  
  1153.     rot = 0;                            // clear rotation accumulator
  1154.  
  1155.     ran = (UBYTE)rnd();                    // throw a dice
  1156.     if (ran > scent) {                    // if number over scent hurdle...
  1157.         if ((UBYTE)rnd() > creat->right ) rot = rot + 1;
  1158.         if ((UBYTE)rnd() > creat->left  ) rot = rot - 1;
  1159.  
  1160.         creat->dir += rot;
  1161.         creat->dir &= 7;                // force into 0..7
  1162.  
  1163. #ifndef FASTER
  1164.         IFAUDIT if (VISION && scent) printf(" .. And deviated from scent path !! (%d > %d)\n", ran, scent);
  1165. #endif
  1166.     }
  1167.  
  1168. // Calculate tentative forward step (x,y)
  1169.     x = (creat->x + xymovs[creat->dir].dx) & ACRE;    // move into 1 of 8 dirs
  1170.     y = (creat->y + xymovs[creat->dir].dy) & ACRE;
  1171.  
  1172. // If the creature is about to move onto a pixel with food on, "eat it" !
  1173. // Food can be either another bug or simple vegetation.
  1174. // If Bug is mainly a Veggie, there's a strong bias to refusing meat.
  1175. // If Bug is mainly a meat eater, there's a strong bias to refusing vegetation.
  1176.  
  1177.     cell = cell_type(x, y);
  1178. //printf("Cell type bug #%3d is moving towards: %d @ (%d,%d)\n", creat-bugs, cell, x,y);
  1179.     switch (cell) {
  1180.  
  1181.         case VEGE_CELL:
  1182.             if ((UBYTE)rnd() > creat->foodtype) {    // small FOODTYPE = VEGETARIAN
  1183.  
  1184.                 IFAUDIT printf("Bug #%3d Eats Vegetation @ (%d,%d) (+%d E, NEW: %d) (GENE=%3d% (%s))\n",
  1185.                     creat-bugs,x,y, FOOD_ENERGY, creat->energy + FOOD_ENERGY,
  1186.                     creat->foodtype*100/256,
  1187.                     creat->foodtype>128?"CARNIVORE":"HERBIVORE");
  1188.  
  1189.                 creat->energy += FOOD_ENERGY;    // if food found, eat it.
  1190.                 food_in_system--;                // track amount of food left
  1191.             } else {
  1192.                 IFAUDIT printf("Bug #%3d avoids Vegetation (GENE=%3d% (%s))\n",
  1193.                     creat-bugs, creat->foodtype*100/256,
  1194.                     creat->foodtype>128?"CARNIVORE":"HERBIVORE");
  1195.  
  1196.                 break;    // don't fall through. Food obstructs move !
  1197.             }
  1198.  
  1199.             // Now fall through as if moving onto empty cell. **!!
  1200.  
  1201.  
  1202.         case NEUT_CELL:
  1203.             erase_cell(creat);                // erase old position
  1204.  
  1205.             creat->x = x;                    // move to new cell position
  1206.             creat->y = y;
  1207.  
  1208. //            color = 1 + (creat->energy >> color_divider);
  1209. //            color = color < VEGE_CELL ? color : VEGE_CELL-1;
  1210.             color = VEGE_CELL-1;
  1211.  
  1212.             set_cell_to(x,y, color, creat);
  1213.             if ( *(owner_ptrs+x+(y<<9)) ) {
  1214.                 BUGPTR rogue;
  1215.  
  1216.                 rogue = *(owner_ptrs+x+(y<<9));
  1217.  
  1218.                 printf("FATAL BUG: supposedly EMPTY cell contains an owner back-ptr !\n");
  1219.                 printf("Dangling back-ptr : %08X (bug # %d)\n", rogue, rogue-bugs);
  1220.                 printf("Corresponds to following bug:\n");
  1221.                 printf("%s, (%d,%d), (empty cell x,y = %d,%d)\n",
  1222.                     rogue->alive?"ALIVE":"DEAD", rogue->x, rogue->y, x, y);
  1223.             }
  1224.                 
  1225.             *(owner_ptrs+x+(y<<9)) = creat;    // update parallel array
  1226.             break;
  1227.  
  1228.         case WALL_CELL:                        // don't move in case of wall !
  1229.             break;
  1230.  
  1231.         default:                // default case SHOULD mean bumping into bug...
  1232.  
  1233.             victim = *(owner_ptrs + x + (y<<9));
  1234.  
  1235.             if (victim) {
  1236.             if ((UBYTE)rnd() < creat->foodtype) {    // large FOODTYPE = CARNIVORE
  1237.  
  1238.                 IFAUDIT printf("Bug #%3d wants to eat bug #%3d @ (%d,%d) (GENE=%3d% (%s))\n",
  1239.                     creat-bugs,victim-bugs,x,y,
  1240.                     creat->foodtype*100/256,
  1241.                     creat->foodtype>128?"CARNIVORE":"HERBIVORE");
  1242.  
  1243.                 if (victim->energy < creat->energy) {
  1244.  
  1245.                     creat->energy += victim->energy;    // eat weaker creature
  1246.  
  1247.                     IFAUDIT printf("Bug #%3d Eats Bug #%3d (+%d E NEW: %d)!\n",
  1248.                         creat-bugs, victim-bugs, victim->energy, creat->energy);
  1249.  
  1250.                     victim->alive = FALSE;                // kill victim
  1251.                     deaths++;
  1252.                     erase_cell(victim);                    // erase old position
  1253.  
  1254.                     erase_cell(creat);                    // erase old position
  1255.                     creat->x = x;                        // move to new cell position
  1256.                     creat->y = y;
  1257.     
  1258. //                    color = 1 + (creat->energy >> color_divider);
  1259. //                    color = color < VEGE_CELL ? color : VEGE_CELL-1;
  1260.                     color = VEGE_CELL-1;
  1261.  
  1262.                     set_cell_to(x,y, color, creat);
  1263.                     
  1264.                     *(owner_ptrs+x+(y<<9)) = creat;        // update parallel array
  1265.                     
  1266.                 } else {
  1267.                     IFAUDIT printf("Bug #%3d Avoids Eating Bug #%3d because 2nd bug is stronger!\n",
  1268.                         creat-bugs, victim-bugs);
  1269.                 }
  1270.  
  1271.             } else {
  1272.                 IFAUDIT printf("Bug #%3d avoids Bug @ (%d,%d) (+%d E, NEW: %d) (GENE=%3d% (%s))\n",
  1273.                     creat-bugs,x,y, FOOD_ENERGY, creat->energy + FOOD_ENERGY,
  1274.                     creat->foodtype*100/256,
  1275.                     creat->foodtype>128?"CARNIVORE":"HERBIVORE");
  1276.             }
  1277.             }
  1278.     }
  1279. }
  1280. //----------------------------------------------------------------
  1281. // OLD Oxygen stuff originally straight after age++;
  1282. //----------------------------------------------------------------
  1283. //    oxygen += creat->oxy_produce;        // discharge by-product O2
  1284.  
  1285. //    if (oxygen >= creat->oxy_consume) {    // if O2-breathing, and if there's
  1286. //        oxygen -= creat->oxy_consume;    // enough O2 : grab your quota
  1287. //    } else creat->energy = 0;            // otherwise you suffocate
  1288. //
  1289. //    carb_dioxide += creat->co2_produce;
  1290. //    if (carb_dioxide >= creat->co2_consume) {        // idem with CO2
  1291. //        carb_dioxide -= creat->co2_consume;
  1292. //    } else creat->energy = 0;
  1293.  
  1294.  
  1295.  
  1296. //---------------------------------------------------------------------------
  1297. // This routine handles the details of giving birth to a new creature.
  1298. //
  1299. // 1) ASEXUAL
  1300. // Basically, a dead bug structure is found and then the parent is cloned
  1301. // in this space. The gene variables of the parent are slightly mutated
  1302. // in the child.
  1303. //
  1304. // 2) SEXUAL
  1305. // A dead bug structure is found and then the child genes are created from
  1306. // a mixture of both parent's genes.
  1307. //
  1308. // The energy exchange which happens is as follows:
  1309. //  - the child gets 30 % of the mother's energy
  1310. //  - the mother's energy goes down to 70%
  1311. //
  1312. // For sexual reproduction both parents drop to 85% of their previous level.
  1313. //---------------------------------------------------------------------------
  1314.  
  1315. void spawn_child (BUGPTR mother, BUGPTR father, FLAG sexy) {
  1316.  
  1317. BUGPTR child;
  1318.  
  1319. int i;
  1320.  
  1321.     child = &bugs[0];
  1322.  
  1323.     for (i=0; i< MAX_BUGS; i++, child++) {    // scan array to find empty slot..
  1324.  
  1325.         if (!child->alive) {
  1326.  
  1327.             births++;                    // record birth
  1328.  
  1329.             *child            = *mother;    // copy mother's genes for starters..
  1330.                                         // This means:
  1331.                                         // child->x            == mother->x
  1332.                                         // child->y            == mother->y
  1333.                                         // child->prevpix    == mother->prevpix
  1334.  
  1335.  
  1336.             child->age        = 0;        // new-born !
  1337.             child->generation++;        // a new generation !
  1338.  
  1339.             if (sexy) {
  1340.                 child->energy        = (WORD) (
  1341.                                     30 * (    (int) mother->energy +
  1342.                                             (int) father->energy    ) / 100) ;
  1343.                 mother->energy        = (WORD) ((85 * (int)mother->energy) / 100);
  1344.                 father->energy        = (WORD) ((85 * (int)father->energy) / 100);
  1345.  
  1346.                 child->right        = mix(mother->right,    father->right);
  1347.                 child->left            = mix(mother->left,        father->left);
  1348.                 child->vision        = mix(mother->vision,    father->vision);
  1349.                 child->sexuality    = mix(mother->sexuality,father->sexuality);
  1350.                 child->dirgene        = mix(mother->dirgene,    father->dirgene);
  1351.                 child->dying_age    = mix(mother->dying_age,father->dying_age);
  1352.                 child->minsexage    = mix(mother->minsexage,father->minsexage);
  1353.                 child->maxsexage    = mix(mother->maxsexage,father->maxsexage);
  1354.                 child->speed        = mix(mother->speed,    father->speed);
  1355.                 child->foodtype        = mix(mother->foodtype,    father->foodtype);
  1356.                 child->procr_energy    = mix(mother->procr_energy,    father->procr_energy);
  1357.             } else {
  1358.                 child->energy        = (WORD) ((30 * (int)mother->energy) / 100);
  1359.                 mother->energy        = (WORD) ((70 * (int)mother->energy) / 100);
  1360.  
  1361.                 child->right        = mutate (child->right);
  1362.                 child->left            = mutate (child->left );
  1363.                 child->vision        = mutate (child->vision);
  1364.                 child->sexuality    = mutate (child->sexuality);
  1365.                 child->dirgene        = mutate (child->dirgene);
  1366.                 child->dying_age    = mutate (child->dying_age);
  1367.                 child->minsexage    = mutate (child->minsexage);
  1368.                 child->maxsexage    = mutate (child->maxsexage);
  1369.                 child->speed        = mutate (child->speed);
  1370.                 child->foodtype        = mutate (child->foodtype);
  1371.                 child->procr_energy    = mutate (child->procr_energy);
  1372.             }
  1373.  
  1374.                     // whizz away from mother in a gene dependent way
  1375.             child->dir            = (child->dir +(child->dirgene>>5)) % 8;
  1376.  
  1377.             child->speed_delay    = child->speed >> 6;    // 0..3
  1378.  
  1379.             return;
  1380.         }
  1381.     }
  1382. }
  1383. //----------------------------------------------------------------
  1384. // Slightly modify a gene (a variable in the unsigned range 0..255).
  1385. // The variable is not allowed to wrap-around, but instead "hits the
  1386. // ceiling".
  1387. //
  1388. // Note that the mutation coding is subtle. The mutation should not
  1389. // have any bias towards lowering or increasing the gene's value **!!
  1390. // It should be STRICTLY random !
  1391. //----------------------------------------------------------------
  1392. UBYTE mutate    (UBYTE gene) {
  1393.  
  1394. int newgene;
  1395.  
  1396.     newgene = gene + rnd()%MUTATE_RANGE - rnd()%MUTATE_RANGE;
  1397.  
  1398.     if (newgene > 255) return 255;
  1399.     else
  1400.     if (newgene < 0  ) return 0;
  1401.  
  1402.     return (UBYTE) newgene;
  1403. }
  1404. //----------------------------------------------------------------
  1405. // Mix the 2 genes of two parent creatures to produce a child's gene.
  1406. //----------------------------------------------------------------
  1407. UBYTE mix        (UBYTE gene1, UBYTE gene2) {
  1408.  
  1409.     return mutate( (UBYTE) (( (UWORD)gene1 + (UWORD)gene2 ) /2 ));
  1410. }
  1411.  
  1412. //----------------------------------------------------------------
  1413. // Drop some food in our world on a spot which IS NOT YET FOOD.
  1414. // We can't put food on food OR food on a bug otherwise our food stats
  1415. // will be inaccurate.
  1416. //----------------------------------------------------------------
  1417. void grow_food(void) {
  1418.  
  1419. short fx,fy;
  1420. UBYTE food=VEGE_CELL;
  1421. int dummy;
  1422. register int attempts;
  1423. double ra,rr;                // random angle (in rads)
  1424.  
  1425. // modulate food growth with night/day
  1426. // From 0..50 modulate growth between 50% and 100%
  1427. // Between 51..100 food growth is always 100%
  1428.  
  1429.     if (rnd()%100 > (daylight+50)) return;
  1430.  
  1431.     attempts = 20;                        // attemps at finding empty spot..
  1432.  
  1433.     while (attempts--) {
  1434.         if (OASIS_SIZE) {
  1435.  
  1436.             ra = (double) rnd();                // pick a random dot inside a circle
  1437.             rr = (double) (rnd() % OASIS_SIZE);
  1438.  
  1439.             fx =  ACRE/2 + (int) (cos(ra) * rr);
  1440.             fy =  ACRE/2 + (int) (sin(ra) * rr);
  1441.  
  1442.         } else {
  1443.             fx = (rnd()%ACRE) & (-X_AND);
  1444.  
  1445.             dummy = fx * fx * attempts;                // introduce random delay
  1446.             dummy /= 20;                    // randomness stems from data-depen
  1447.  
  1448.             fy = (rnd()%ACRE) & (-Y_AND);
  1449.         }
  1450.  
  1451.         fx &= ACRE;                            // ensure we stay within the ACRE
  1452.         fy &= ACRE;
  1453.  
  1454.         if (is_empty(fx, fy)) {
  1455.             set_cell_to(fx,fy, food, &dummy_bug);
  1456.             food_in_system++;            // track amount of food in our world
  1457.             break;
  1458.         }
  1459.     }
  1460. }
  1461. //----------------------------------------------------------------
  1462. // Gain access to system function libraries (Dynamic Link Libraries).
  1463. //----------------------------------------------------------------
  1464. void open_libraries(void) {
  1465.  
  1466.     IntuitionBase    = (void*) OpenLibrary("intuition.library",0);
  1467.     if (!IntuitionBase) {
  1468.         printf("MAJOR PROBLEM: Couldn't open INTUITION library!\n");
  1469.         exit(FATAL_ERROR);
  1470.     }
  1471.  
  1472.     GfxBase            = (void*) OpenLibrary("graphics.library",0);
  1473.     if (!GfxBase) {
  1474.  
  1475.         CloseLibrary((struct Library *) IntuitionBase);
  1476.  
  1477.         printf("MAJOR PROBLEM: Couldn't open GRAPHICS library!\n");
  1478.         exit(FATAL_ERROR);
  1479.     }
  1480.  
  1481.     RexxSysBase        = (void*) OpenLibrary("rexxsyslib.library",0);
  1482.     if (!RexxSysBase) {
  1483.  
  1484.         printf("AREXX Not available. All of MegaJitter's AREXX functions are disabled.\n");
  1485.         printf("If you do have AREXX on your system, please run RexxMast to start AREXX,\n");
  1486.         printf("next time before you start MegaJitter.\n\n");
  1487.     }
  1488. }
  1489. //----------------------------------------------------------------
  1490. // Check any user options.
  1491. //
  1492. // For example, the program can be evoked as follows:
  1493. //
  1494. // 1> MJ INIT_FOOD 2000 INIT_BUGS 20 SEX AUDIT
  1495. //----------------------------------------------------------------
  1496.  
  1497. FLAG get_user_options( void ) {
  1498.  
  1499. struct RDArgs *rdargs;
  1500. struct variable *var;
  1501.  
  1502. #ifndef DEBUG
  1503.     if (! (rdargs = ReadArgs(MJIT_DOS_TEMPLATE, (ULONG*) &options, NULL))) {
  1504.         printf("ERROR: ARGUMENTS INCORRECT.\n");
  1505.         printf("Type MegaJitter ? for a full syntax template.\n\n");
  1506.  
  1507.         return SYNTAX_ERROR;
  1508.  
  1509.     } // Free RDA only AFTER we've parsed ptrs in options pointing into RDA **!!
  1510.  
  1511. #endif
  1512.  
  1513. // Initialize device independent cell handlers (visual routines are the default)
  1514.  
  1515.     if (NOANIM) {
  1516.         cell_writer        = blind_put_cell;    // all of these are POINTERS to
  1517.         cell_eraser        = blind_wipe_cell;    // routines.
  1518.         cell_typer        = blind_cell_type;
  1519.         food_checker    = blind_is_food;
  1520.         clear_checker    = blind_is_empty;
  1521.     } else {
  1522.         cell_writer        = gfx_put_cell;
  1523.         cell_eraser        = gfx_wipe_cell;
  1524.         cell_typer        = asm_read_pixel;
  1525.         food_checker    = asm_is_food;
  1526.         clear_checker    = asm_is_empty;
  1527.     }
  1528.  
  1529. // If user didn't select the NTSC option and MJ thinks it is running on an
  1530. // NTSC machine, ask user if it wishes to switch NTSC compatibility mode on.
  1531.  
  1532.     if (!NTSC && SysBase->ex_EClockFrequency != 709379 ) {
  1533.         if (quick_req("I think this is an NTSC machine!", "CORRECT|NOPE"))
  1534.             NTSC = TRUE;
  1535.     }
  1536.  
  1537. // Any non-initialized simulation globals get initialized now.
  1538.  
  1539.     init_defaults(&varlist[0]);            // others are intialized from CMD line.
  1540.  
  1541. // **!! NOW we can free RDA (AFTER we've parsed ptrs)
  1542.  
  1543.     FreeArgs(rdargs);
  1544.  
  1545. // Most sanity checks can be performed from pre-set data...
  1546.  
  1547.     var = &varlist[0];
  1548.     while(var->name) {
  1549.  
  1550.         if (*var->address > var->max_val) {
  1551.             printf("%s has to be in the range [%d..%d] ! (%d > %d)\n",
  1552.                 var->name, var->min_val, var->max_val, *var->address, var->max_val);
  1553.             exit(SYNTAX_ERROR);
  1554.         } else
  1555.  
  1556.         if (*var->address < var->min_val) {
  1557.             printf("%s has to be in the range [%d..%d] ! (%d < %d)\n",
  1558.                 var->name, var->min_val, var->max_val, *var->address, var->min_val);
  1559.             exit(SYNTAX_ERROR);
  1560.         }
  1561.  
  1562.         var++;                    // goto next var in list
  1563.     }
  1564.  
  1565. // Check user-initialized parameters for outrageous values.
  1566. // Inform user of range of variables if out of bounds.
  1567.  
  1568.     if (INIT_BUGS > MAX_BUGS) {
  1569.         printf("INIT_BUGS can not be larger than MAX_BUGS! (%d > %d)\n",
  1570.                     INIT_BUGS, MAX_BUGS);
  1571.         return SYNTAX_ERROR;
  1572.     }
  1573.  
  1574. // Copy MAX_BUGS into full scale value field of numbugs statistic.
  1575.  
  1576.     available_stats[0].scale = MAX_BUGS;
  1577.  
  1578. // Show user the resulting scenario settings, if requested.
  1579.  
  1580.     if (SHOWDEFAULTS) {
  1581.  
  1582.         dumpdefaults((void*)0);
  1583.  
  1584.         printf("\n\nHit ENTER to continue...\n");
  1585.         getch();
  1586.     }
  1587.  
  1588. // If we want to capture all simulation data & statistics, open recording file.
  1589.  
  1590.     if (CAPTURE) {
  1591.         capture_file = Output();        // **!! TEMPORARY
  1592.     }
  1593.  
  1594.     return 0;
  1595. }
  1596.  
  1597. //----------------------------------------------------------------
  1598. //
  1599. //----------------------------------------------------------------
  1600. RC dumpdefaults(void* dummy) {
  1601.  
  1602.     printf("audit        = %d        (%08X)\n",REPORT,REPORT);
  1603.     printf("capture        = %d        (%08X)\n",CAPTURE,CAPTURE);
  1604.     printf("noanim        = %d        (%08X)\n",NOANIM,NOANIM);
  1605.     printf("vision        = %d        (%08X)\n",VISION,VISION);
  1606.     printf("sex        = %d        (%08X)\n",SEX,SEX);
  1607.     printf("MAX_BUGS    = %d        (%08X)\n",MAX_BUGS,MAX_BUGS);
  1608.     printf("\n");
  1609.     printf("INIT_BUGS    = %d        (%08X)\n",INIT_BUGS,INIT_BUGS);
  1610.     printf("INIT_FOOD    = %d        (%08X)\n",INIT_FOOD,INIT_FOOD);
  1611.     printf("INIT_ENERGY    = %d        (%08X)\n",INIT_ENERGY,INIT_ENERGY);
  1612.     printf("INIT_VARIANCE    = %d        (%08X)\n",INIT_VARIANCE,INIT_VARIANCE);
  1613.     printf("MUTATE_RANGE    = %d        (%08X)\n",MUTATE_RANGE,MUTATE_RANGE);
  1614.     printf("FOOD_RATE    = %d        (%08X)\n",FOOD_RATE,FOOD_RATE);
  1615.     printf("FOOD_ENERGY    = %d        (%08X)\n",FOOD_ENERGY,FOOD_ENERGY);
  1616.     printf("X_AND        = %d        (%08X)\n",X_AND,X_AND);
  1617.     printf("Y_AND        = %d        (%08X)\n",Y_AND,Y_AND);
  1618.     printf("OASIS_SIZE    = %d        (%08X)\n",OASIS_SIZE,OASIS_SIZE);
  1619. //        printf("INIT_O2        = %d        (%08X)\n",INIT_O2,INIT_O2);
  1620. //        printf("INIT_CO2    = %d        (%08X)\n",INIT_CO2,INIT_CO2);
  1621.  
  1622.     return TRUE;
  1623. }
  1624.  
  1625. //----------------------------------------------------------------
  1626. // Set all non-initialized Simulation Global Parameters to a default value
  1627. // IF the user hasn't given a value himself.
  1628. //----------------------------------------------------------------
  1629. void init_defaults    (struct variable *varptr) {
  1630.  
  1631. ULONG *var;
  1632.  
  1633.     while (varptr->name) {
  1634.         var = varptr->address;
  1635.  
  1636.         if (*var) {                            // if RDA initialized a ptr to an arg,
  1637.             *var = atoi((char*) *var);        // convert ASCII arg to number
  1638.         } else {
  1639.             *var = varptr->init_val;        // else use built-in default value.
  1640.         }
  1641.  
  1642.         varptr++;                // goto next variable
  1643.     }
  1644. }
  1645. //----------------------------------------------------------------
  1646. // Before every main loop : reset and recalc some global vars.
  1647. //----------------------------------------------------------------
  1648. void reset_global_stats() {
  1649.  
  1650. //int i;
  1651.  
  1652.     // Calculate the mapping factor to go from
  1653.     //    creat->energy   to  creature pixel/cell number (as a right shift)
  1654.  
  1655. //    color_divider    = (MAX_ENERGY+FOOD_ENERGY) / MAX_COLORS;
  1656.  
  1657. //    for (i=0; i< 30; i++) {            // determine howmuch to right shift
  1658. //        if (color_divider) {
  1659. //            color_divider >>= 1;
  1660. //        } else break;
  1661. //    }
  1662.  
  1663. //    i--;
  1664. //    color_divider = i;
  1665.     // printf("SHIFTS = %d\t\t\t%d>>%d=%d\n\n", i, MAX_ENERGY+FOOD_ENERGY, i, (MAX_ENERGY+FOOD_ENERGY)>
  1666.  
  1667. //---------------------------------------------------------------
  1668. // reset some statistics counters
  1669.  
  1670.     total_age        = 0;
  1671.     total_energy    = 0;
  1672.     total_right        = 0;
  1673.     total_left        = 0;
  1674.     total_vision    = 0;
  1675.     total_sexuality    = 0;
  1676.     total_dying_age = 0;
  1677.     total_minsexage    = 0;
  1678.     total_maxsexage    = 0;
  1679.     total_speed        = 0;
  1680.     total_foodtype    = 0;
  1681.     total_procr        = 0;
  1682. //    total_O2        = 0;
  1683. //    total_CO2        = 0;
  1684.  
  1685.     max_right= max_left= max_vision    = max_dying_age = max_speed = 0;
  1686.     min_right= min_left= min_vision    = min_dying_age = min_speed = 255;
  1687.  
  1688.     max_foodtype = max_sexuality = max_minsexage = max_maxsexage = 0;
  1689.     min_foodtype = min_sexuality = min_minsexage = min_maxsexage = 255;
  1690.  
  1691.     max_procr= 0;
  1692.     min_procr= 255;
  1693. }
  1694.  
  1695. //----------------------------------------------------------------
  1696. // For every live creature: collect some of its current settings.
  1697. //----------------------------------------------------------------
  1698.  
  1699. #define    update_minmax(v,min,max)    \
  1700. if ( (v) > (max) ) (max) = (v);\
  1701. if ( (v) < (min) ) (min) = (v)
  1702.  
  1703. void collect_bug_stats (BUGPTR creat) {
  1704.  
  1705.     total_age        += creat->age;
  1706.     total_energy    += creat->energy;        // track various simulation
  1707.     total_left        += creat->left;            // variables and/or results
  1708.     total_right        += creat->right;
  1709.     total_vision    += creat->vision;
  1710.     total_sexuality    += creat->sexuality;
  1711.     total_dying_age    += creat->dying_age;
  1712.     total_minsexage += creat->minsexage;
  1713.     total_maxsexage += creat->maxsexage;
  1714.     total_speed        += creat->speed;
  1715.     total_foodtype    += creat->foodtype;
  1716.     total_procr        += creat->procr_energy;
  1717.  
  1718. //    total_O2        += creat->oxy_produce;
  1719. //    total_CO2        += creat->co2_produce;
  1720.  
  1721. //    total_O2        -= 255 - creat->co2_produce;
  1722. //    total_CO2        -= 255 - creat->oxy_produce;
  1723.  
  1724. // update some minima & maxima.
  1725.  
  1726.     update_minmax (creat->right        ,min_right        ,max_right);
  1727.     update_minmax (creat->left        ,min_left         ,max_left );
  1728.     update_minmax (creat->vision    ,min_vision        ,max_vision);
  1729.     update_minmax (creat->sexuality    ,min_sexuality    ,max_sexuality);
  1730.     update_minmax (creat->maxsexage    ,min_maxsexage    ,max_maxsexage);
  1731.     update_minmax (creat->minsexage    ,min_minsexage    ,max_minsexage);
  1732.     update_minmax (creat->dying_age    ,min_dying_age    ,max_dying_age);
  1733.     update_minmax (creat->speed        ,min_speed        ,max_speed);
  1734.     update_minmax (creat->foodtype    ,min_foodtype    ,max_foodtype);
  1735.     update_minmax (creat->procr_energy    ,min_procr    ,max_procr);
  1736. }
  1737.  
  1738. //----------------------------------------------------------------
  1739. // From the numeric statistics collected, draw some pretty graphics.
  1740. //----------------------------------------------------------------
  1741. void    update_statistics() {
  1742.  
  1743. int linelen;
  1744.  
  1745. // Print Time.
  1746. //------------
  1747.  
  1748.     lineptr = linebuf;                            // reset stats output line.
  1749.  
  1750.     if ((time&(TIMER_SPEED-1)) == 0) {
  1751.         SetAPen(stat_rp, 2);
  1752.         sprintf(strbuf,"Time = %8d", time);        // convert number to N-digit string
  1753.         WriteString(240, CHAR_HEIGHT, strbuf);
  1754.     }
  1755.  
  1756.     if (time == TIMER_SPEED) {
  1757.         sprintf(strbuf,"Runs = %4d", runs);        // convert number to N-digit string
  1758.         WriteString(240, 2*CHAR_HEIGHT, strbuf);
  1759.     }
  1760.  
  1761. // Check if it's time to update the stats on the screen...
  1762.  
  1763.     if (time&(graph_speed-1)) return;
  1764.  
  1765.     if (CAPTURE) {
  1766.         lineptr = stpcpy(lineptr, strbuf);
  1767.         *lineptr++ = ',';
  1768.     }
  1769.  
  1770. // Scroll graphs one pixel to the left, this gives a kind of medical EEC
  1771. // effect like real-time traces.
  1772. // Since graphs are in plane 0 only, just scroll plane 0 for speed.
  1773.  
  1774.     stat_rp->Mask = 1;                            // use bitplane 0 only
  1775.     SetAPen(stat_rp, 0);                        // for numbers graph
  1776.     RectFill(stat_rp, 0, 400, 112, 511);        // erase all numbers
  1777.     SetAPen(stat_rp, 1);
  1778.  
  1779.     ScrollRaster(stat_rp, 1,0, LE, STATS_TOPY-1, STAT_SCR_WIDTH-1, STAT_WIN_HEIGHT-1);
  1780.     stat_rp->Mask = 3;                            // restore normal mask
  1781.  
  1782. // Calculate population-wide averages (IF numbugs <> 0 to avoid DIV BY ZERO)
  1783.  
  1784.     if (numbugs) {
  1785.         total_age        /= numbugs;
  1786.         total_energy    /= numbugs;
  1787.         total_right        /= numbugs;
  1788.         total_left        /= numbugs;
  1789.         total_vision    /= numbugs;
  1790.         total_sexuality    /= numbugs;
  1791.         total_speed        /= numbugs;
  1792.         total_foodtype    /= numbugs;
  1793.  
  1794.         total_maxsexage = (total_maxsexage<<8)    / numbugs;        // scaled to 0.. 64K
  1795.         total_minsexage = (total_minsexage<<4)    / numbugs;        // scaled to 0..4096
  1796.         total_dying_age = (total_dying_age<<8)    / numbugs;
  1797.         total_procr        = (total_procr<<6)        / numbugs;        // scaled to 0.. 16K
  1798.     }
  1799.  
  1800.     PaintStatValues();                            // draw all stats
  1801.  
  1802.     if (CAPTURE) {                                // if stats CAPTURE is on, dump them.
  1803.         *lineptr++ = LF; linelen = lineptr - linebuf;
  1804.         Write (capture_file, linebuf, linelen);
  1805.     }
  1806.  
  1807.     births = deaths = 0;                        // they accumulate for every update
  1808. }
  1809.  
  1810. //----------------------------------------------------------------
  1811. // Time to update the stats graphs.
  1812. // Go through all stats, and if they're currently on display, print them.
  1813. //----------------------------------------------------------------
  1814. void PaintStatValues    (void) {
  1815.  
  1816. struct statistic *stat;
  1817. UBYTE min,max;
  1818. UWORD i;
  1819. ULONG *stat_ptr;
  1820.  
  1821.     graphnum    = 1;                        // start drawing statistics graphs
  1822.     stat        = &available_stats[0];        // statistic entry
  1823.     for (i=0; i< NUM_STATS; i++, stat++) {
  1824.  
  1825.             // record stat in its own buffer.
  1826.         stat_ptr = stat->buffer + stat_bufix;        // record basic stat
  1827.         *stat_ptr = *stat->stat_addr;
  1828.  
  1829.         if (stat->minmax_addr) {
  1830.             stat_ptr += 256;
  1831.             *stat_ptr = (ULONG) *stat->minmax_addr;        // record minimum too
  1832.  
  1833.             stat_ptr += 256;
  1834.             *stat_ptr = (ULONG) *(stat->minmax_addr+1);    // and maximum.
  1835.         }
  1836.  
  1837.         if (graphnum > MAX_GRAPHS) continue;
  1838.  
  1839.         if (stat->displayed) {
  1840.             print_stat    (stat, *stat->stat_addr, STAT_SCR_WIDTH-1);
  1841.             if ( (time&(2*graph_speed-1)) && stat->minmax_addr && MINMAX) {
  1842.                 min = *stat->minmax_addr;      print_minmax(stat, min, STAT_SCR_WIDTH-1);
  1843.                 max = *(stat->minmax_addr+1); print_minmax(stat, max, STAT_SCR_WIDTH-1);
  1844.             }
  1845.             graphnum++;
  1846.         }
  1847.     }
  1848.  
  1849.     stat_bufix++;                        // index is byte, so wraps around at 255.
  1850. }
  1851.  
  1852. //----------------------------------------------------------------
  1853. // The user has selected a new mix of statistics to be displayed.
  1854. // We have to redraw all stats from their buffers.
  1855. //
  1856. // This is done without scrolling but simply by plotting for X=LE to SCR_WIDTH
  1857. //----------------------------------------------------------------
  1858. void RePaintGraphs    (void) {
  1859.  
  1860. struct statistic *stat;
  1861. UBYTE ptr, min,max;
  1862. UWORD i, x;
  1863. ULONG value;
  1864. FLAG oldcapture;
  1865.  
  1866.     oldcapture = CAPTURE; CAPTURE = FALSE;    // stop value dumping while repainting
  1867.  
  1868.     NUMERIC_STATS = FALSE;                    // stop numerical output while "
  1869.  
  1870.     SetAPen(stat_rp, 1);                    // Use pen 1 for graphs
  1871.  
  1872.     stat_rp->Mask = 1;                        // SCROLL bitplane 0 only
  1873.  
  1874. // in the for loop, ptr wraps around 255 to reach final value.
  1875.     for (x=LE, ptr = stat_bufix+1; ptr != stat_bufix; x++, ptr++) {
  1876.  
  1877.         graphnum    = 1;                        // start drawing statistics graphs
  1878.  
  1879.         stat        = available_stats;            // 1st statistic entry
  1880.         for (i=0; i< NUM_STATS; i++, stat++) {
  1881.             if (graphnum > MAX_GRAPHS) break;
  1882.  
  1883.             if (stat->displayed) {
  1884.                 value = *(stat->buffer + ptr);    // get a recorded stat value
  1885.                 print_stat    (stat, value, x);
  1886.                 if ((x&1) && stat->minmax_addr && MINMAX ) {
  1887.                     min = *(stat->buffer +ptr +256); print_minmax(stat, min, x);
  1888.                     max = *(stat->buffer +ptr +512); print_minmax(stat, max, x);
  1889.                 }
  1890.                 graphnum++;
  1891.             }
  1892.         }
  1893.     }
  1894.  
  1895.     stat_rp->Mask = 3;                            // restore normal mask
  1896.  
  1897.     CAPTURE = oldcapture;                        // restore CAPTURE status
  1898.  
  1899.     NUMERIC_STATS = TRUE;
  1900. }
  1901.  
  1902. //----------------------------------------------------------------
  1903. // Print a new statistic
  1904. //    - graphically and
  1905. //    - numerically (if enabled)
  1906. //
  1907. // The graph is scaled to be 64 pixels fullscale.
  1908. // The numerical output is unscaled.
  1909. //----------------------------------------------------------------
  1910.  
  1911. void print_stat (struct statistic *stat, ULONG num, int x) {
  1912.  
  1913. int scalednum;
  1914. register int y;
  1915.  
  1916.     scalednum= (num << 6 ) / stat->scale;        // scale full scale to 0..63
  1917.  
  1918.     if (stat->flip_graph) {
  1919.         y = CURGRAPH_Y -GRAPH_HEIGHT + scalednum;
  1920.         WritePixel(stat_rp, x, y-1);
  1921.  
  1922.         if (NUMERIC_STATS) {
  1923.             sprintf(strbuf,"%5d", stat->scale -num);    // convert number to N-digit string
  1924.             WriteString(LE-50, CURGRAPH_Y-3, strbuf);
  1925.         }
  1926.     } else {
  1927.  
  1928.         y = CURGRAPH_Y- scalednum;
  1929.         WritePixel(stat_rp, x, y-1);
  1930.  
  1931.         if (NUMERIC_STATS) {
  1932.             sprintf(strbuf,"%5d", num);            // convert number to N-digit string
  1933.             WriteString(LE-50, CURGRAPH_Y-3, strbuf);
  1934.         }
  1935.     }
  1936.  
  1937. // If simulation data capture is enabled, record stats in file.
  1938.  
  1939.     if (CAPTURE) {
  1940.         lineptr = stpcpy(lineptr, strbuf);
  1941.         *lineptr++ = ',';
  1942.     }
  1943. }
  1944. //----------------------------------------------------------------
  1945. // Print minima and maxima of a statistic
  1946. //    - graphically
  1947. //
  1948. // The graph is scaled to be 64 pixels fullscale.
  1949. //----------------------------------------------------------------
  1950.  
  1951. void print_minmax (struct statistic *stat, UBYTE value, int x) {
  1952.  
  1953. register int y;
  1954.  
  1955.     value = value >> 2;
  1956.  
  1957.     if (stat->flip_graph) {
  1958.         y = CURGRAPH_Y -GRAPH_HEIGHT + value;    WritePixel(stat_rp, x, y-1);
  1959.     } else {
  1960.         y = CURGRAPH_Y- value;                    WritePixel(stat_rp, x, y-1);
  1961.     }
  1962. }
  1963. //----------------------------------------------------------------
  1964. // Initialize Ecosystem related data structures ...
  1965. //
  1966. // Dynamically allocate:
  1967. // - (512*512) back-pointers array    (1 Mb **!!)
  1968. // - (512*512) cell array            (256 K)
  1969. // - array of BUGS structures        (10 K for default 300 bugs)
  1970. // - statistics buffers                (50 K roughly)
  1971. //----------------------------------------------------------------
  1972. void alloc_structs    (void) {
  1973.  
  1974. UWORD i;
  1975. struct statistic *stat;
  1976.  
  1977. // Get back-pointer 2-D Array
  1978.     owner_ptrs = (struct bug **) AllocMem(PTR_MAP_SIZE, MEMF_CLEAR);
  1979.     if (!owner_ptrs) {
  1980.         printf("FATAL INIT: Failed to allocate creature back-pointers map.\n");
  1981.         exit(FATAL_ERROR);
  1982.     }
  1983.  
  1984. // Get 2-D Cell array
  1985.     environment = AllocMem(SCREEN_WIDTH*SCREEN_WIDTH, MEMF_CLEAR);
  1986.     if (!environment) {
  1987.         printf("FATAL INIT: Couldn't allocate RAM for environment !!\n");
  1988.         exit(40);
  1989.     }
  1990.  
  1991. // Get Array of Bug structs
  1992.     bugs = (BUGPTR) AllocMem (MAX_BUGS*sizeof(struct bug), MEMF_CLEAR);
  1993.     if (!bugs) {
  1994.         printf("FATAL INIT: Failed to allocate pool for creatures.\n");
  1995.         exit(FATAL_ERROR);
  1996.     }
  1997.  
  1998. // Allocate statistics buffers
  1999.     stat = available_stats;
  2000.     for (i=0; i< NUM_STATS; i++) {
  2001.         stat->buffer = AllocMem(3*256*4, MEMF_CLEAR);
  2002.         if (!stat->buffer) {
  2003.             printf("FATAL INIT: Couldn't allocate RAM for Statistics buffer #%d !!\n", i);
  2004.             exit(40);
  2005.         }
  2006.         stat++;
  2007.     }
  2008. }
  2009.  
  2010. //----------------------------------------------------------------
  2011. // Reset the entire ecosystem.
  2012. //
  2013. // Spray        INIT_FOOD food parcels.
  2014. // Initialize    INIT_BUGS random creatures.
  2015. //----------------------------------------------------------------
  2016. FLAG reset_ecosystem (void) {
  2017.  
  2018. struct statistic *stat;
  2019. BUGPTR creat;
  2020. UWORD i;
  2021.  
  2022. // Draw an informative dividing line between previous simulation run and present
  2023. // Only draw a dividing line for statistics which are active.
  2024.  
  2025.     SetAPen(stat_rp,1);
  2026.  
  2027.     Move(stat_rp, STAT_SCR_WIDTH-1, STATS_TOPY);
  2028.  
  2029.     graphnum = 1;
  2030.     stat = &available_stats[0];                        // -> list of stats.
  2031.     for (i=0; i< NUM_STATS; i++) {
  2032.  
  2033.         if (graphnum > MAX_GRAPHS) continue;
  2034.  
  2035.         if (stat->displayed) {
  2036.             Draw(stat_rp, STAT_SCR_WIDTH-1, STATS_TOPY+graphnum*GRAPH_HEIGHT-1);
  2037.             graphnum++;
  2038.         }
  2039.  
  2040.         stat++;
  2041.     }
  2042.  
  2043. // Initialize food environment.
  2044.  
  2045.     wipe_environment();                // level playing field
  2046.  
  2047.     food_in_system    = 0;
  2048.     daylight        = 100;            // ensure full daylight (no modulation)
  2049.     for (i=0; i< INIT_FOOD; i++) {                    // throw some food...
  2050.         grow_food();
  2051.     }
  2052.  
  2053. // Initialize a RANDOM pool of creatures (fertile, infertile, weak, strong, ...)
  2054.  
  2055.     creat = &bugs[0];
  2056.     for (i=0; i< MAX_BUGS; i++, creat++) {
  2057.         creat->alive = FALSE;                        // set all bugs to dead
  2058.     }
  2059.  
  2060.     creat = &bugs[0];
  2061.     for (i=0; i< INIT_BUGS; i++, creat++) {            // create a couple of
  2062.         creat->alive        = TRUE;                    // random 1st-generation
  2063.  
  2064.         creat->energy        = INIT_ENERGY + (INIT_ENERGY * rnd()%20 / 100);
  2065.                                             // + max 20% of INIT_ENERGY
  2066.         creat->x            = rnd()&ACRE;
  2067.         creat->y            = rnd()&ACRE;
  2068.         creat->dir            = rnd()&7;                // creatures
  2069.  
  2070.         creat->generation    = 0;
  2071.         creat->age            = 0;
  2072.  
  2073.         creat->right        = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2074.         creat->left            = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2075.         creat->vision        = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2076.         creat->sexuality    = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2077.         creat->dying_age    = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2078.         creat->speed        = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2079.         creat->foodtype        = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2080.         creat->procr_energy    = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2081.  
  2082.         creat->minsexage    = rnd()%32;                // give 'em a break !
  2083.         creat->maxsexage    = 255 -rnd()%INIT_VARIANCE;
  2084.  
  2085.         creat->dirgene        = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2086.         creat->oxy_produce    = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2087.         creat->oxy_consume    = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2088.         creat->co2_produce    = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2089.         creat->co2_consume    = (128-INIT_VARIANCE/2) + rnd()%INIT_VARIANCE;
  2090.  
  2091.         creat->speed_delay    = creat->speed >> 5;    // 0..7
  2092.  
  2093.         creat->prevpix.pixel_byte_offs= 0;    // all 1st pixels erase (0,0)
  2094.         creat->prevpix.pixel_bit_no   = 0;
  2095.     }
  2096.     
  2097. //    oxygen            = INIT_O2;                // primordial atmosphere
  2098. //    carb_dioxide    = INIT_CO2;
  2099.  
  2100.     food_timer        = FOOD_RATE;            // start food timer.
  2101.  
  2102.     time            = 0;                    // Big Bang !
  2103.  
  2104.     runs++;                                    // track number of simulation runs
  2105.  
  2106.     return TRUE;
  2107. }
  2108. //----------------------------------------------------------------
  2109. // Erase all food and/or bugs from environment.
  2110. //----------------------------------------------------------------
  2111. void wipe_environment(void) {
  2112.  
  2113. register int i;
  2114. register ULONG *clr;
  2115.  
  2116.     if (!NOANIM)
  2117.         BltClear(bm->Planes[0], ECO_SCR_DEPTH*SCREEN_HEIGHT*SCREEN_WIDTH/8, 0);
  2118.  
  2119. // Wipe all cells
  2120.     
  2121.     clr = (ULONG*) environment;
  2122.     for (i=0; i< (512*512/(4*4)); i++) {
  2123.         *clr++ = 0;
  2124.         *clr++ = 0;
  2125.         *clr++ = 0;
  2126.         *clr++ = 0;
  2127.     }
  2128.  
  2129. // Wipe all back-ptrs.
  2130.  
  2131.     clr = (ULONG*) owner_ptrs;
  2132.     for (i=0; i< (512*512/4); i++) {
  2133.         *clr++ = 0;
  2134.         *clr++ = 0;
  2135.         *clr++ = 0;
  2136.         *clr++ = 0;
  2137.     }
  2138. }
  2139. //----------------------------------------------------------------
  2140. // Initialize graphics-related program elements.
  2141. //
  2142. // - open the Statistics Screen
  2143. // - if animated simulation, also open the Eco-system Screen
  2144. //----------------------------------------------------------------
  2145. #ifndef    MONOCHROME
  2146.  UWORD    eco_colors[NUM_COLORS] =
  2147.     {0xFFF, 0xAAA, 0x999, 0x888, 0x777, 0x666, 0x555, 0x444,    //
  2148.      0x333, 0x222, 0x111, 0x111, 0x000, 0x000,                    // CREATURES
  2149.      0x000, 0x000};                                                // WALL, FOOD
  2150.  
  2151.  UWORD    stat_colors[4] = {0x111, 0xFF0, 0xC00, 0xFFF};
  2152. #else
  2153.  UWORD    eco_colors[NUM_COLORS] =
  2154.     {0xFFF, 0xEEE, 0xAAA, 0x888,
  2155.      0x666, 0x444, 0x222, 0x555};
  2156.  
  2157.  UWORD    stat_colors[4] = {0x000, 0xFF0, 0xFFF, 0xFFF};
  2158. #endif
  2159.  
  2160. //----------------------------------------------------------------
  2161. void init_gfx (void) {
  2162.  
  2163.     if (NTSC)    MAX_GRAPHS = 6;                            // reduced size Screen !!
  2164.     else        MAX_GRAPHS = 8;
  2165.  
  2166.     graph_speed        = 64;                                // NORMAL graph speed
  2167.  
  2168.     STAT_WIN_HEIGHT    = (MAX_GRAPHS*GRAPH_HEIGHT + STATS_TOPY);    // enough for N graphs
  2169.  
  2170.     ns.Width        = STAT_SCR_WIDTH;
  2171.     ns.Height        = STAT_WIN_HEIGHT+12;
  2172.     ns.Depth        = STAT_SCR_DEPTH;
  2173.     ns.Font            = &txtattr;
  2174.     stat_screen        = (void*) OpenScreen(&ns);
  2175.  
  2176.     if (!stat_screen) {
  2177.         printf("FATAL INIT: Failed to open its %dx%d resolution Statistics screen!\n",
  2178.             STAT_SCR_WIDTH, STAT_WIN_HEIGHT+12);
  2179.         printf("NTSC Users: kindly add the NTSC flag to the command line so that MJ\n");
  2180.         printf("opens a NTSC-compatible Screen. (I've been unable to unambiguously\n");
  2181.         printf("determine whether a system is running NTSC or PAL. Sorry.\n");
  2182.         exit(FATAL_ERROR);
  2183.     }
  2184.  
  2185.     LoadRGB4(&stat_screen->ViewPort, &stat_colors[0], 4);
  2186.  
  2187.     vi        = GetVisualInfo(stat_screen, TAG_DONE);
  2188.  
  2189.     nw.Height = STAT_WIN_HEIGHT;
  2190.     nw.Screen = stat_screen;
  2191.     window = OpenWindow(&nw);
  2192.  
  2193.     if (!window) {
  2194.         printf("FATAL INIT: Failed to open Statistics window !\n");
  2195.  
  2196.         CloseScreen(stat_screen);
  2197.         FreeVisualInfo(vi);
  2198.         exit(FATAL_ERROR);
  2199.     }
  2200.  
  2201.     append_stats_menus();                    // finish off NewMenu array
  2202.     menustrip = CreateMenus(mymenus, TAG_DONE);    // Create MenuStrip
  2203.  
  2204.     if (!menustrip) {
  2205.         printf("FATAL INIT: Unable to create MenuStrip!\n");
  2206.  
  2207.         CloseWindow(window);
  2208.         CloseScreen(stat_screen);
  2209.         FreeVisualInfo(vi);
  2210.         exit(FATAL_ERROR);
  2211.     }
  2212.  
  2213.     LayoutMenus(menustrip, vi, TAG_DONE);    // Position Menus & Items
  2214.     SetMenuStrip(window, menustrip);        // Attach menu to window
  2215.  
  2216. // Disable some menu items related to disabled features (or not-implemented).
  2217.  
  2218.     if (! SEX)        OffMenu(window, FULLMENUNUM(STATS_MENU, SEX_ITEM, 0));
  2219.     if (! VISION)    OffMenu(window, FULLMENUNUM(STATS_MENU, EYE_ITEM, 0));
  2220.  
  2221. // **!! Not implemented
  2222.  
  2223.     OffMenu(window, FULLMENUNUM(PROJECT_MENU, PROJ_MENU_LOAD,        0));
  2224.     OffMenu(window, FULLMENUNUM(PROJECT_MENU, PROJ_MENU_SAVE,        0));
  2225.     OffMenu(window, FULLMENUNUM(OPTIONS_MENU, OPT_MENU_CTRL_PANEL,    0));
  2226.  
  2227.     OffMenu(window, FULLMENUNUM(STATS_MENU, OXY_ITEM, 0));
  2228.     OffMenu(window, FULLMENUNUM(STATS_MENU, CO2_ITEM, 0));
  2229.  
  2230.     stat_rp = window->RPort;
  2231.  
  2232.     PaintStatLabels();                        // Draw initial stat variables
  2233.  
  2234. //----------------------------------------------------
  2235.  
  2236.     if (! NOANIM) {
  2237.  
  2238.         bm = AllocBitMap(SCREEN_WIDTH, SCREEN_HEIGHT, ECO_SCR_DEPTH,
  2239.                 BMF_CLEAR | BMF_DISPLAYABLE | BMF_INTERLEAVED, NULL);
  2240.  
  2241.         if(!bm) {
  2242.             printf("FATAL INIT: Failed to AllocBitMap() contiguous 512*512*4 Eco bitmap!\n");
  2243.  
  2244.             CloseWindow(window);
  2245.             CloseScreen(stat_screen);
  2246.             FreeVisualInfo(vi);
  2247.             exit(FATAL_ERROR);
  2248.         }
  2249.  
  2250.     // Note the INTERLEAVED bitmap organization for max pixel performace **!!
  2251.  
  2252.         eco_screen = (void*) OpenScreenTags(    NULL,
  2253.                                                 SA_DisplayID,    HIRESLACE_KEY,
  2254.                                                 SA_Interleaved,    TRUE,
  2255.                                                 SA_Width,         SCREEN_WIDTH,
  2256.                                                 SA_Height,        SCREEN_HEIGHT,
  2257.                                                 SA_Depth,        ECO_SCR_DEPTH,
  2258.                                                 SA_Title,        scr_name,
  2259.                                                 SA_ShowTitle,    FALSE,
  2260.                                                 SA_BitMap,        bm,
  2261.                                                 TAG_END
  2262.                                             );
  2263.  
  2264.         if (!eco_screen) {
  2265.             printf("FATAL INIT: Failed to open 512x512 Eco Screen!\n");
  2266.  
  2267.             FreeBitMap(bm);
  2268.             CloseWindow(window);
  2269.             CloseScreen(stat_screen);
  2270.             if (vi) FreeVisualInfo(vi);
  2271.             exit(FATAL_ERROR);
  2272.         }
  2273.  
  2274.         LoadRGB4(&eco_screen->ViewPort, &eco_colors[0], NUM_COLORS);
  2275.     
  2276.         plane0    = (ULONG*) eco_screen->RastPort.BitMap->Planes[0];
  2277.     }
  2278. }
  2279. //-------------------------------------------------------------------------
  2280. // Print the statistics labels and draw the horizontals separating graphs.
  2281. //-------------------------------------------------------------------------
  2282. void PaintStatLabels (void) {
  2283.  
  2284. struct statistic *stat;
  2285. UWORD i;
  2286.  
  2287.     SetAPen(stat_rp, 2);
  2288.  
  2289.     graphnum    = 1;    // offset so that Text aligns with base of graph
  2290.     stat        = available_stats;                // statistic entry
  2291.     for (i=0; i< NUM_STATS; i++, stat++) {
  2292.  
  2293.         if (graphnum > MAX_GRAPHS) break;
  2294.  
  2295.         if (stat->displayed) {
  2296.  
  2297.             WriteString( 3, CURGRAPH_Y-3, stat->label);
  2298.             graphnum++;
  2299.         }
  2300.     }
  2301.  
  2302.     i = graphnum;
  2303.     graphnum = 0;
  2304.     while (i--) {
  2305.         Move(stat_rp, LE, CURGRAPH_Y-1);
  2306.         Draw(stat_rp, STAT_SCR_WIDTH-1, CURGRAPH_Y-1);
  2307.         graphnum++;
  2308.     }
  2309. }
  2310. //-------------------------------------------------------------------------
  2311. // Here we finish off the rest of the array of NewMenu structs.
  2312. //
  2313. // Part of the MenuStrip is dynamically generated at init time from the
  2314. // list of STATISTICAL VARIABLES.
  2315. //-------------------------------------------------------------------------
  2316.  
  2317. void append_stats_menus(void) {
  2318.  
  2319. register struct NewMenu *newmenu;
  2320. register struct statistic *stat;
  2321. UWORD i;
  2322.  
  2323.     IFAUDIT mymenus[NEWMENU_AUDIT].nm_Flags |= CHECKED;
  2324.  
  2325.     newmenu = mymenus + NEWMENU_APPEND;    // -> first empty slot
  2326.     for (i=0; i< NUM_STATS; i++) {
  2327.         stat = &available_stats[i];
  2328.  
  2329.         newmenu->nm_Type        = NM_ITEM;
  2330.         newmenu->nm_Label        = stat->label;
  2331.         newmenu->nm_CommKey        = NULL;
  2332.         newmenu->nm_Flags        = CHECKIT|MENUTOGGLE;
  2333.             if (stat->displayed) newmenu->nm_Flags |= CHECKED;
  2334.         newmenu->nm_MutualExclude = 0L;
  2335.  
  2336.         newmenu++;
  2337.     }
  2338.  
  2339.     newmenu->nm_Type    = NM_END;    // Terminate NewMenu array with the required
  2340.     newmenu->nm_Label    = NULL;        // end marker
  2341.     newmenu->nm_CommKey    = NULL;
  2342.     newmenu->nm_Flags    = 0;
  2343.     newmenu->nm_MutualExclude = 0L;
  2344.  
  2345.     auto_reset = TRUE;
  2346. }
  2347. //----------------------------------------------------------------
  2348. // Modify the list of selected statistics to be displayed on the screen.
  2349. //
  2350. // Since Intuition allows several menuitems to be CHECKed and un-CHECKed
  2351. // without sending an IntuiMessage for each change, we have to go through
  2352. // all MenuItems, checking their state, and possibly un-setting some so
  2353. // that we don't exceed MAX_GRAPHS current graps on the Stats Screen.
  2354. //
  2355. //----------------------------------------------------------------
  2356. void    toggle_stat    ( void ) {
  2357.  
  2358. struct statistic *stat;
  2359. UWORD i;
  2360.  
  2361.     stat = available_stats;                    // statistics array
  2362.     for (i=0; i< NUM_STATS; i++) {
  2363.  
  2364.         if (menuitem_checkstate(STATS_MENU, i))    stat->displayed = TRUE;
  2365.         else                                    stat->displayed = FALSE;
  2366.  
  2367.         stat++;
  2368.     }
  2369.  
  2370.     graphnum    = 1;
  2371.     stat = available_stats;                    // statistics array
  2372.     for (i=0; i< NUM_STATS; i++) {
  2373.  
  2374.         if (graphnum > MAX_GRAPHS) {
  2375.             stat->displayed = FALSE;
  2376.             uncheck_menuitem(STATS_MENU, i);
  2377.         }
  2378.  
  2379.         if (stat->displayed) graphnum++;
  2380.  
  2381.         stat++;
  2382.     }
  2383.     
  2384.     SetRast(stat_rp, 0);                    // erase screen
  2385.     PaintStatLabels();                        // redraw labels
  2386.     RePaintGraphs();                        // and redraw graphs from buffers
  2387. }
  2388.  
  2389. //----------------------------------------------------------------
  2390. // Take away a menuitem's CheckMark (the tick on the left).
  2391. //----------------------------------------------------------------
  2392. void uncheck_menuitem (int menunum, int itemnum) {
  2393.  
  2394. struct Menu        *menu;
  2395. struct MenuItem    *menuitem;
  2396.  
  2397.     menu    = menustrip;                    // -> Linked list of Menus.
  2398.     while (menunum--) {
  2399.         menu    = menu->NextMenu;            // -> first item in this menu
  2400.     }
  2401.  
  2402.     menuitem = menu->FirstItem;
  2403.     while(itemnum--) {
  2404.         menuitem = menuitem->NextItem;        // find Nth menu item
  2405.     }
  2406.  
  2407.     menuitem->Flags &= ~CHECKED;            // un-set CHECK mark !
  2408. }
  2409.  
  2410. //----------------------------------------------------------------
  2411. // return whether this menuitem has his checkmark SET or CLEAR.
  2412. //----------------------------------------------------------------
  2413. FLAG menuitem_checkstate (int menunum, int itemnum) {
  2414.  
  2415. struct Menu        *menu;
  2416. struct MenuItem    *menuitem;
  2417.  
  2418.     menu    = menustrip;                    // -> Linked list of Menus.
  2419.     while (menunum--) {
  2420.         menu    = menu->NextMenu;            // -> first item in this menu
  2421.     }
  2422.  
  2423.     menuitem = menu->FirstItem;
  2424.     while(itemnum--) {
  2425.         menuitem = menuitem->NextItem;        // find Nth menu item
  2426.     }
  2427.  
  2428.     return (FLAG) (menuitem->Flags & CHECKED);            // test CHECK mark
  2429. }
  2430.  
  2431. //----------------------------------------------------------------
  2432. // "Blind" cell-manipulation routines.
  2433. // These maintain a consistent ecosystem in an array of byte cells,
  2434. // not a screen full of pixels representing cells, as is usual.
  2435. //----------------------------------------------------------------
  2436.  
  2437. #define    cell_offs(x,y)    ( (x) + (( (UWORD)(y) ) <<9 ) )
  2438.  
  2439. //----------------------------------------------------------------
  2440. void blind_put_cell (ULONG x, ULONG y, ULONG cell, BUGPTR bug) {
  2441.  
  2442. #ifdef DEBUG
  2443.     if (x>511 || y>511) printf("Bug: blind_put_cell(%d,%d) !\n", x,y);
  2444. #endif
  2445.  
  2446.     *(environment + cell_offs(x,y)) = cell;
  2447. }
  2448. //----------------------------------------------------------------
  2449. void blind_wipe_cell (BUGPTR bug) {
  2450.  
  2451. register ULONG offs;
  2452.  
  2453.     offs = cell_offs(bug->x, bug->y);
  2454.  
  2455.     *(environment+    offs)    = NEUT_CELL;
  2456.     *(owner_ptrs+    offs)    = (BUGPTR) 0L;
  2457. }
  2458. //----------------------------------------------------------------
  2459. CELL blind_cell_type (ULONG x, ULONG y) {
  2460.  
  2461. #ifdef DEBUG
  2462.     if (x>511 || y>511) printf("Bug: blind_cell_type(%d,%d) !\n", x,y);
  2463. #endif
  2464.  
  2465.     return *(environment+cell_offs(x,y)) ;
  2466. }
  2467. //----------------------------------------------------------------
  2468. FLAG blind_is_food (ULONG x, ULONG y) {
  2469.  
  2470. #ifdef DEBUG
  2471.     if (x>511 || y>511) printf("Bug: blind_is_food(%d,%d) !\n", x,y);
  2472. #endif
  2473.  
  2474.     return (FLAG) (*(environment+cell_offs(x,y)) == VEGE_CELL);
  2475. }
  2476. //----------------------------------------------------------------
  2477. FLAG blind_is_empty (ULONG x, ULONG y) {
  2478.  
  2479. #ifdef DEBUG
  2480.     if (x>511 || y>511) printf("Bug: blind_is_empty(%d,%d) !\n", x,y);
  2481. #endif
  2482.  
  2483.     return (FLAG) (*(environment+cell_offs(x,y)) == NEUT_CELL);
  2484. }
  2485. //================================================================
  2486. void gfx_put_cell (ULONG x, ULONG y, ULONG cell, BUGPTR bug) {
  2487.  
  2488. #ifdef DEBUG
  2489.     if (x>511 || y>511) printf("Bug: gfx_put_cell(%d,%d) !\n", x,y);
  2490. #endif
  2491.  
  2492.     asm_plot_pixel(&bug->prevpix, x,y, cell );
  2493. }
  2494. //----------------------------------------------------------------
  2495. void gfx_wipe_cell (BUGPTR bug) {
  2496.  
  2497.     asm_fastwipe_pixel(&bug->prevpix);
  2498.  
  2499.     *(owner_ptrs+    cell_offs(bug->x, bug->y))    = (BUGPTR) 0L;
  2500. }
  2501. //----------------------------------------------------------------
  2502. // Clean up Simulation-related things before returning to OS.
  2503. //----------------------------------------------------------------
  2504. void close_ecosys (void) {
  2505.  
  2506. struct statistic *stat;
  2507. UWORD i;
  2508.  
  2509.     FreeMem((char*)environment,    SCREEN_WIDTH*SCREEN_WIDTH);
  2510.     FreeMem((char*)owner_ptrs,    PTR_MAP_SIZE);
  2511.     FreeMem((char*)bugs,        MAX_BUGS*sizeof(struct bug));
  2512.  
  2513.     stat = available_stats;
  2514.     for (i=0; i< NUM_STATS; i++) {            // free all statistics buffers
  2515.         FreeMem(stat->buffer, 3*256*4);
  2516.         stat++;
  2517.     }
  2518. }
  2519. //----------------------------------------------------------------
  2520. // Clean up graphics-related things before returning to OS.
  2521. //----------------------------------------------------------------
  2522. void close_gfx (void) {
  2523.  
  2524. #ifdef AMIGA
  2525.  
  2526.     if (IntuitionBase) {
  2527.  
  2528.         if (window) {
  2529.             if (menustrip) {
  2530.                 ClearMenuStrip(window);
  2531.                 FreeMenus(menustrip);
  2532.             }
  2533.             CloseWindow(window);
  2534.         }
  2535.  
  2536.         if (stat_screen) CloseScreen(stat_screen);
  2537.  
  2538.         if (vi) FreeVisualInfo(vi);
  2539.  
  2540.         if (!NOANIM) {
  2541.             if (eco_screen) CloseScreen(eco_screen);
  2542.             if (bm) FreeBitMap(bm);
  2543.         }
  2544.  
  2545.         CloseLibrary((struct Library *) IntuitionBase);
  2546.     }
  2547.  
  2548.     if (GfxBase) CloseLibrary((struct Library *)GfxBase);
  2549.  
  2550.     if (RexxSysBase) CloseLibrary((struct Library *)RexxSysBase);
  2551.     
  2552. #endif
  2553. }
  2554.  
  2555. //-------------------------------------------------------------------------
  2556. // Check if there are any Intuition Events waiting for us.
  2557. // Process them according to their type.
  2558. //-------------------------------------------------------------------------
  2559.  
  2560. void handle_IDCMP_msgs    (void) {
  2561.  
  2562. struct IntuiMessage *msg;
  2563. ULONG msgtype;
  2564. SHORT msgcode;
  2565. SHORT mousex,mousey;
  2566. APTR  IAddr;                        // ptr to Intuition object (Gadget,..)
  2567.  
  2568.     // For Intuition Messages use the gadtools GetMsg/ReplyMsg variants
  2569.     // so that gadtools can intercept gadget clicks which it (and not we)
  2570.     // should process (e.g. for CYCLE_KIND or LISTVIEW_KIND gadgets !).
  2571.  
  2572.     while (msg = GT_GetIMsg(window->UserPort)) {
  2573.  
  2574.           msgtype    = msg->Class;    // copy Message fields and
  2575.         msgcode    = msg->Code;
  2576.         mousex    = msg->MouseX;
  2577.         mousey    = msg->MouseY;
  2578.         IAddr    = msg->IAddress;
  2579.  
  2580.         GT_ReplyIMsg(msg);        // reply swiftly
  2581.  
  2582. #ifdef    DEBUGX
  2583. printf("IDCMP MSGTYPE:%8lx (CODE:%8lx) ", msgtype, msgcode);
  2584.         switch (msgtype) {
  2585.             case CLOSEWINDOW:    printf("CLOSEWINDOW\n"); break;
  2586.             case ACTIVEWINDOW:    printf("ACTIVEWINDOW\n"); break;
  2587.             case MENUPICK:        printf("MENUPICK:\n"); break;
  2588.             case MOUSEMOVE:        printf("MOUSEMOVE:\n"); break;
  2589.             case MOUSEBUTTONS:    printf("MOUSEBUTTONS\n"); break;
  2590.             case VANILLAKEY:    printf("VANILLAKEY\n"); break;
  2591.             case GADGETUP:        printf("GADGETUP:\n"); break;
  2592.             case INTUITICKS:    printf("INTUITICKS\n"); break;
  2593.             case REFRESHWINDOW:    printf("REFRESHWINDOW\n"); break;
  2594.             default:            printf("-- UNKNOWN --\n");
  2595.         }
  2596. #endif
  2597.         switch (msgtype) {
  2598.         //    case CLOSEWINDOW:    handle_quit();                    break;
  2599.         //    case ACTIVEWINDOW:    handle_activation();            break;
  2600.             case MENUPICK:        handle_menuselection(msgcode);    break;
  2601.         //    case MOUSEMOVE:        handle_mousemove();                break;
  2602.         //    case MOUSEBUTTONS:    handle_click();                    break;
  2603.         //    case VANILLAKEY:    handle_keypress( (char) msgcode); break;
  2604.         //    case GADGETUP:        handle_gadgets();                break;
  2605.         //    case INTUITICKS:    break;
  2606.         //    case REFRESHWINDOW:    GT_BeginRefresh((struct Window*)IAddr);
  2607.         //                        GT_EndRefresh((struct Window*)IAddr, TRUE);
  2608.         //                        break;
  2609.             default:
  2610.                 printf("BUG: Unknown IDCMP MSGTYPE:%x (CODE:%x)\n", msgtype, msgcode);
  2611.         }
  2612.     }
  2613. }
  2614.  
  2615. //-------------------------------------------------------------------------
  2616. // A MENUPICK event has arrived.
  2617. // The user selected a meny item somewhere.
  2618. // Find out which Menu, which Menuitem and possibly which sub-item.
  2619. //-------------------------------------------------------------------------
  2620. void handle_menuselection(SHORT menu) {
  2621.  
  2622.     switch (MENUNUM(menu)) {
  2623.  
  2624.         //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2625.  
  2626.         case PROJECT_MENU:
  2627.             switch (ITEMNUM(menu)) {
  2628.                         //--------------------------------------------------------
  2629.                 case PROJ_MENU_RESET:
  2630.  
  2631.                     if (quick_req("Sure you want to reset Ecosystem ?", "YES|NO")) {
  2632.                         reset_ecosystem();
  2633.                     }
  2634.  
  2635.                     break;
  2636.  
  2637.                         //--------------------------------------------------------
  2638.                 case PROJ_MENU_LOAD:
  2639.                     break;
  2640.                         //--------------------------------------------------------
  2641.                 case PROJ_MENU_SAVE:
  2642.                     break;
  2643.                         //--------------------------------------------------------
  2644.                 case PROJ_MENU_ABOUT:
  2645.                     popup_About_req();
  2646.                     break;
  2647.                         //--------------------------------------------------------
  2648.                 case PROJ_MENU_AUTHOR:
  2649.                     popup_Author_req();
  2650.                     break;
  2651.                         //--------------------------------------------------------
  2652.                 case PROJ_MENU_QUIT:
  2653.                     if (quick_req("Sure you want to quit?", "YES|NO")) {
  2654.                         quit_me = TRUE;
  2655.                     }
  2656.                     break;
  2657.             }
  2658.             break;
  2659.  
  2660.         //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2661.  
  2662.         case OPTIONS_MENU:
  2663.             switch (ITEMNUM(menu)) {
  2664.  
  2665.                 case OPT_MENU_SIM_SPEED:
  2666.                     switch(SUBNUM(menu)) {
  2667.                         case 0: sim_speed = 0    ; break;
  2668.                         case 1: sim_speed = 15    ; break;
  2669.                     }
  2670.                     break;
  2671.  
  2672.                 case OPT_MENU_STAT_SPEED:
  2673.                     switch(SUBNUM(menu)) {
  2674.                         case 0: graph_speed =1024; break;
  2675.                         case 1: graph_speed = 512; break;
  2676.                         case 2: graph_speed = 256; break;
  2677.                         case 3: graph_speed =  64; break;    // Default
  2678.                         case 4: graph_speed =  16; break;
  2679.                         case 5: graph_speed =   8; break;
  2680.                         case 6: graph_speed =   4; break;
  2681.                     }
  2682.                     break;
  2683.  
  2684.                 case OPT_MENU_RESET:    auto_reset    = ~auto_reset;    break;
  2685.                 case OPT_MENU_AUDIT:    REPORT        = ~REPORT;        break;
  2686.                 case OPT_MENU_MINMAX:    MINMAX        = ~MINMAX;        break;
  2687.             }
  2688.             break;
  2689.  
  2690.         //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2691.  
  2692.         case STATS_MENU:
  2693.             toggle_stat();
  2694.             break;
  2695.     }
  2696. }
  2697.  
  2698. //-------------------------------------------------------------------------
  2699. // REXX Support routines follow..
  2700. //-------------------------------------------------------------------------
  2701.  
  2702. //-------------------------------------------------------------------------
  2703. // Create REXX port.
  2704. //
  2705. // Insert our PUBLIC port in front of the list so that the rest of the world
  2706. // can find us quickly, bypassing lethargic priority 0 ports.
  2707. //-------------------------------------------------------------------------
  2708. FLAG post_REXX_port(char * portname) {
  2709.  
  2710.     rexx_port = CreatePort(portname, 50L);
  2711.  
  2712.     if (rexx_port) return TRUE; else return FALSE;
  2713. }
  2714. //-------------------------------------------------------------------------
  2715. // Close down REXX communications port. (but first flush port of late commers)
  2716. //-------------------------------------------------------------------------
  2717. void close_REXX(void) {
  2718.  
  2719. struct RexxMsg *msg;
  2720.  
  2721.     Forbid();    // the whole operation should be atomic !
  2722.  
  2723.     while (msg = (struct RexxMsg*) GetMsg((struct MsgPort*) rexx_port)) {
  2724.  
  2725.         msg->rm_Result1 = RC_FATAL;
  2726.         msg->rm_Result2 = 999;
  2727.     
  2728.  
  2729.         ReplyMsg((struct Message*)msg);        // reply to the REXX resident process
  2730.     }
  2731.  
  2732.     DeletePort(rexx_port);
  2733.  
  2734.     Permit();
  2735. }
  2736. //-------------------------------------------------------------------------
  2737. // Check if there are any REXX commands waiting for us.
  2738. //-------------------------------------------------------------------------
  2739.  
  2740. void handle_AREXX_msgs    (void) {
  2741.  
  2742. struct RexxMsg *msg;
  2743.  
  2744.     while (msg = (struct RexxMsg*) GetMsg((struct MsgPort*) rexx_port)) {
  2745.  
  2746.         if (! IsRexxMsg(msg)) {
  2747.             printf("\n");
  2748.             printf("WARNING ! MegaJitter is receiving rogue non-AREXX messages addressed\n");
  2749.             printf("to its AREXX message port.. please ask programs not to send these\n");
  2750.             printf("type of messages. Thanks.\n\n");
  2751.         } else
  2752.  
  2753.         if ((msg->rm_Action & 0xFF000000 ) != RXCOMM) {
  2754.             printf("REXX Message received which isn't a COMMAND message (Action=%08X)\n",
  2755.                 msg->rm_Action);
  2756.  
  2757.         } else {
  2758.  
  2759.             msg->rm_Result2 = 0;
  2760.  
  2761.             msg->rm_Result1 = parse_rexx_cmd(msg);    // returns as 'RC' in REXX
  2762.         }
  2763.  
  2764.         ReplyMsg((struct Message*)msg);        // reply to the REXX resident process
  2765.     }
  2766. }
  2767. //-------------------------------------------------------------------------
  2768. // We've received a REXX command message containing a string to be
  2769. // analyzed and acted upon.
  2770. //
  2771. // Legal types of REXX commands are:
  2772. //
  2773. // <SIMPLE_CMD>                        /* This should be a single token */
  2774. //
  2775. // <VARIABLE> <decimal value>        /* This would assign value to variable */
  2776. //
  2777. //-------------------------------------------------------------------------
  2778. RC parse_rexx_cmd(struct RexxMsg* msg) {
  2779.  
  2780. struct variable *var;
  2781. struct command  *cmd;
  2782. char *str, *str2;
  2783. ULONG newval;
  2784.  
  2785.     str = msg->rm_Args[0];
  2786.  
  2787. //printf("AREXX command received : '%s'\n", str);
  2788.  
  2789.     while (*str == ' ' || *str == '\t') str++;        // skip leading white spc.
  2790.     str2 = str;
  2791.  
  2792.     // find end of first token (if only token, token is terminated by \0 !)
  2793.  
  2794.     while ( *str2 > ' ') str2++;
  2795.  
  2796.     *str2++ = 0;                                    // turn 1st token into C-string
  2797.  
  2798. // Try to match any of our single-word commands...
  2799.  
  2800.     cmd = &cmdlist[0];
  2801.     while(cmd->name) {
  2802.  
  2803.         if (strcmp(str, cmd->name) == 0) {
  2804.             // printf("Executing command '%s' from REXX..\n", cmd->name);
  2805.  
  2806.             return (*cmd->address)( msg );            // call function via pointer.
  2807.  
  2808.             // printf("Done.\n");
  2809.         }
  2810.  
  2811.         cmd++;                        // goto next command in list
  2812.     }
  2813.  
  2814. // Then try to match any global variables which we allow to be changed.
  2815.  
  2816.     var = &varlist[0];                                // go through all var descriptors
  2817.     while (var->name) {
  2818.  
  2819.         if (var->flags & PARAMETER) {
  2820.  
  2821.     // And check if REXX command wants us to assign a value to this variable.
  2822.  
  2823.             if (strcmp(str, var->name) == 0) {
  2824.                 
  2825.                 while (*str2 == ' ' || *str2 == '\t') str2++;    // skip white spc.
  2826.  
  2827.                 newval = atoi(str2);                // read new value
  2828.  
  2829.     // if assigned value is within legal range of this variable, assign it.
  2830.  
  2831.                 if (newval >= var->min_val && newval <= var->max_val) {
  2832.  
  2833.                     *var->address = newval;
  2834.                     // printf("VAR %s set to %d\n", var->name, *var->address);
  2835.                     return 0;                                // and we're done..
  2836.  
  2837.                 } else return REXXERR_VAL_OUTSIDE_RANGE;        // if outside range : ERROR !
  2838.             }
  2839.         }
  2840.         var++;
  2841.     }
  2842.  
  2843.     return REXXERR_UNKNOWN_CMD;                                // 'invalid variable name'
  2844. }
  2845.  
  2846. //-------------------------------------------------------------------------
  2847. // AREXX Commands:
  2848. //
  2849. // "SEX"
  2850. // "VISION"
  2851. // "NOSEX"
  2852. // "NOVISION"
  2853. //-------------------------------------------------------------------------
  2854. RC enable_sex (void *dummy) {
  2855.  
  2856.     if (!SEX) {
  2857.         OnMenu(window, FULLMENUNUM(STATS_MENU, SEX_ITEM, 0));
  2858.         SEX = TRUE;
  2859.         return TRUE;
  2860.     }
  2861.     return FALSE;
  2862. }
  2863.  
  2864. RC enable_vision (void *dummy) {
  2865.  
  2866.     if (!VISION) {
  2867.         OnMenu(window, FULLMENUNUM(STATS_MENU, EYE_ITEM, 0));
  2868.         VISION = TRUE;
  2869.         return TRUE;
  2870.     }
  2871.     return FALSE;
  2872. }
  2873.  
  2874. RC disable_sex (void *dummy) {
  2875.  
  2876.     if (SEX) {
  2877.         OffMenu(window, FULLMENUNUM(STATS_MENU, SEX_ITEM, 0));
  2878.         SEX = FALSE;
  2879.         return TRUE;
  2880.     }
  2881.     return FALSE;
  2882. }
  2883.  
  2884. RC disable_vision (void *dummy) {
  2885.  
  2886.     if (VISION) {
  2887.         OffMenu(window, FULLMENUNUM(STATS_MENU, EYE_ITEM, 0));
  2888.         VISION = FALSE;
  2889.         return TRUE;
  2890.     }
  2891.     return FALSE;
  2892. }
  2893.  
  2894. RC restart (void *dummy) {
  2895.  
  2896.     reset_ecosystem();
  2897.  
  2898.     runs = 1;                // 
  2899.  
  2900.     return TRUE;
  2901. }
  2902. //-------------------------------------------------------------------------
  2903. // AREXX Query commands:
  2904. //
  2905. // "BUGS?"
  2906. // "RUNS?"
  2907. // "TIMESTEPS?"
  2908. //-------------------------------------------------------------------------
  2909.  
  2910. RC return_bugs (void * ptr) {
  2911.  
  2912.     return numbugs;
  2913. }
  2914.  
  2915. RC return_runs (void * ptr) {
  2916.  
  2917.     return runs;
  2918. }
  2919.  
  2920. RC return_timesteps (void * ptr) {
  2921.  
  2922.     return time;
  2923. }
  2924.  
  2925. //-------------------------------------------------------------------------
  2926. // User selected the "About..." option in the Project menu.
  2927. // Give him some info.
  2928. //-------------------------------------------------------------------------
  2929. void popup_About_req(void) {
  2930.  
  2931. static struct EasyStruct aboutES = {
  2932.     sizeof (struct EasyStruct),
  2933.     0,
  2934.     "MegaJitter (C) Laurence Vanhelsuwé 1992-1994", "\
  2935. MegaJitter is a graphical ecosystem simulator featuring:\n\
  2936. \n\
  2937.  - gene-based control over organism's characteristics\n\
  2938.  - mutation of genes at birth\n\
  2939.  - sexual and asexual reproduction\n\
  2940.  - real-time display of entire ecosystem\n\
  2941.  - real-time display of statistics\n\
  2942.  - command line control over ecosystem's global parameters\n\
  2943.  - AREXX interface\n\
  2944. \n\
  2945. MegaJitter is written in 'C' and optimized 030+ assembler.\n" ,
  2946.     "OK",
  2947. };
  2948.  
  2949.     EasyRequest(window, &aboutES, NULL);
  2950. }
  2951. //-------------------------------------------------------------------------
  2952. // User selected the "Author..." option in the Project menu.
  2953. // Give him some info.
  2954. //-------------------------------------------------------------------------
  2955. void popup_Author_req(void) {
  2956.  
  2957. static struct EasyStruct aboutES = {
  2958.     sizeof (struct EasyStruct),
  2959.     0,
  2960.     "MegaJitter (C) Laurence Vanhelsuwé 1992-1994",
  2961. "Address: Laurence Vanhelsuwé\n\
  2962.          Christinastraat 105\n\
  2963.          B-8400 Oostende\n\
  2964.          Belgium\n\
  2965. \n\
  2966. Born   : 18-MAY-1966\n\
  2967. \n\
  2968. E-Mail : not yet (who can give me an Internet box ?)\n" ,
  2969.     "OK",
  2970. };
  2971.  
  2972.     EasyRequest(window, &aboutES, NULL);
  2973. }
  2974. //-------------------------------------------------------------------------
  2975. // This is a generic routine to bring up small message requesters.
  2976. //-------------------------------------------------------------------------
  2977. int quick_req (char *message, char *exit) {
  2978.  
  2979. struct EasyStruct quickES;
  2980.  
  2981.     quickES.es_StructSize    = sizeof (struct EasyStruct);
  2982.     quickES.es_Flags        = 0;
  2983.     quickES.es_Title        = "MegaJitter says...";
  2984.     quickES.es_TextFormat    = message;
  2985.     quickES.es_GadgetFormat    = exit;
  2986.  
  2987.     return EasyRequest(window, &quickES, NULL);
  2988. }
  2989. //----------------------------------------------------------------
  2990. // Print a string at pixel coordinates (x,y)
  2991. //----------------------------------------------------------------
  2992. void WriteString (UWORD x, UWORD y, char *string) {
  2993. int len;
  2994.  
  2995.     len = strlen(string);
  2996. #ifdef AMIGA
  2997.     Move(stat_rp, x, y); Text(stat_rp, string, len);
  2998. #endif
  2999. }
  3000. //----------------------------------------------------------------
  3001. // Returns TRUE if any quitting condition is true.
  3002. // Currently possible conditions:
  3003. //  - quit_me flag is TRUE
  3004. //----------------------------------------------------------------
  3005. FLAG kill_switch    (void) {
  3006.  
  3007.     if (quit_me) return TRUE; else return FALSE;
  3008. }
  3009. //----------------------------------------------------------------
  3010. // Simply set a flag requesting main loop to terminate entire application.
  3011. //----------------------------------------------------------------
  3012. RC please_quit (void *dummy) {
  3013.  
  3014.     quit_me = TRUE;
  3015.  
  3016.     return TRUE;
  3017. }
  3018. //----------------------------------------------------------------
  3019. // Very fast pseudo-random number generator.
  3020. // (Uses the video circuitry's beam position registers.)
  3021. //
  3022. // **!! This obviously won't pass any statistical randomness tests, but
  3023. // it does a reasonable job and the RND() function needs to be super quick
  3024. // since it's called so frequently.
  3025. //----------------------------------------------------------------
  3026. short rnd(void) {
  3027.  
  3028. static unsigned int seed;    // STATIC means the seed stays put between calls
  3029.  
  3030.     seed ^= seed>>16;        // use high word to massage bits of low word.
  3031.  
  3032. #ifdef    AMIGA
  3033.     seed += *(int*)0xdff004;    // use video beam coords regs VPOSR/VHPOSR as random number
  3034. #endif
  3035.  
  3036.     return (short) ((short)seed & (short)0x7FFF);    // return a POSITIVE SHORT integer
  3037. }
  3038. //----------------------------------------------------------------
  3039.