1 /**********************************************************************/
5 /* © Copyright Stefan Winterstein 1993. Freely Distributable. */
7 /**********************************************************************/
12 /* #define DEBUG *//* general debugging output */
13 /* #define ROACHNUMBERING *//* each roach has a number */
14 /* #define USE_WB_WINDOW *//* use WB backdrop window if available (Hack!) */
15 /* #define CHECK_COLLISION *//* roaches turn when bumping into each other */
16 #define INTELLIGENT /* roaches sense near window */
24 int RandInt(int maxVal
);
26 void TurnRoach(Roach
*);
27 void MoveRoach(int rx
);
28 int RoachOverRect(Roach
*, int, int, int, int, unsigned int, unsigned int);
29 int RoachInRect(Roach
*, int, int, int, int, unsigned int, unsigned int);
30 void DrawRoaches(void);
31 void MoveRoaches(void);
32 void RemoveRoaches(void);
33 int MarkHiddenRoaches(void);
34 void checkSquish(void);
35 void ConvertRoachData(void);
36 struct Window
*FindRootWindow(struct Screen
*);
37 struct Bob
*MakeBOBFromData(char *data
, UWORD width
, UWORD height
);
38 void SetupAnimation(void);
39 void CleanExit(LONG ReturnCode
);
40 void Die(const UBYTE
* msg
);
41 int main(int argc
, char **argv
);
47 struct GelsInfo
*GelsInfo
;
48 struct Layer
*myLayer
;
49 struct Layer_Info
*LayerInfo
;
50 char PubScreen
[MAXNAMESIZE
];
54 struct Screen
*Screen
;
56 struct Window
*roachWindow
;
57 struct Window
*userWindow
;
61 * Parameters for SAS/C 6
63 int __oslibversion
= 37; /* for SAS/C auto-init */
64 char __stdiowin
[] = "CON:10/10/600/100/ARoach Output"; /* SAS/C window from WB */
65 long __stack
= 16000; /* enough for 1000 Roaches */
68 * Things for option parsing
70 #define ROACH_LIMIT 1000 /* max. # of roaches */
71 /* depends on __stack */
72 #define ROACH_SPEED 20 /* default speed */
73 #define ROACH_NUM 10 /* default # of roaches */
75 #define TEMPLATE "ROACHES/K/N,SPEED/K/N,SQUISH/S,SCREEN=PUBSCREEN/K,HELP/S"
76 enum { OPT_ROACHES
, OPT_SPEED
, OPT_SQUISH
, OPT_SCREEN
, OPT_HELP
,
81 char ExtendedHelp
[] = /* Yes, ReadArgs() _can_ give extended help! */
83 "ARoach - cockroaches hide under your windows\n"
85 "© Stefan Winterstein 1993. Freely Distributable.\n"
86 "The original Xroach is © 1991 by J.T. Anderson.\n"
88 "\tROACHES=<n> : Number of roaches (default: 10)\n"
89 "\tSPEED=<n> : Speed for the insects (default: 20)\n"
90 "\tSQUISH : Enables roach squishing with mouse click\n"
91 "\tSCREEN=<string> : Name of public screen to run on.\n"
95 * Tags for the roach window
97 struct TagItem roachWindowTags
[] = {
99 {WA_Borderless
, TRUE
},
100 // {WA_SimpleRefresh, TRUE}, /* -> faster, but garbage on screen */
101 {WA_SmartRefresh
, TRUE
},
102 {WA_IDCMP
, IDCMP_MOUSEBUTTONS
},
103 {WA_PubScreenName
, (IPTR
) PubScreen
},
104 {WA_PubScreenFallBack
, TRUE
},
109 * Tags for the user window
111 struct TagItem userWindowTags
[] = {
116 {WA_IDCMP
, IDCMP_CLOSEWINDOW
},
117 {WA_Flags
, WFLG_CLOSEGADGET
+ WFLG_DRAGBAR
+ WFLG_SIZEGADGET
+ WFLG_DEPTHGADGET
+ WFLG_RMBTRAP
},
118 {WA_Title
, (IPTR
) "ARoach"},
119 {WA_PubScreenName
, (IPTR
) PubScreen
},
120 {WA_PubScreenFallBack
, TRUE
},
127 unsigned int display_width
, display_height
;
128 int xoffset
, yoffset
;
134 BOOL squishRoach
= FALSE
;
136 extern RoachMap roachPix
[];
137 extern RoachMap squish
;
138 extern unsigned char ReverseBits
[];
140 /**********************************************************************/
142 /* XRoach functions */
144 /**********************************************************************/
147 Generate random integer between 0 and maxVal-1.
150 #define RandInt(x) RangeRand(x) /* from amiga.lib */
153 * __inline int RandInt(int maxVal)
155 * return ((rand()>>16) % maxVal);
162 Give birth to a roach.
163 i.e. set up "roaches[curRoaches]"
171 if (curRoaches
>= maxRoaches
)
174 r
= &roaches
[curRoaches
++];
175 /* chose a heading */
176 r
->index
= RandInt(ROACH_HEADINGS
);
177 /* find appropriate RoachMap */
178 r
->rm
= &roachPix
[r
->index
];
180 /* Coordinates are for screen, not window */
181 r
->x
= RandInt(display_width
- r
->rm
->width
) + xoffset
;
182 r
->y
= RandInt(display_height
- r
->rm
->height
) + yoffset
;
186 r
->steps
= RandInt(200);
187 r
->turnLeft
= RandInt(100) >= 50;
190 * Generate a bob for this roach.
191 * We find the image in our current RoachMap
193 bob
= MakeBOBFromData(r
->rm
->roachBits
, r
->rm
->width
, r
->rm
->height
);
195 bob
->BobVSprite
->X
= r
->x
;
196 bob
->BobVSprite
->Y
= r
->y
;
198 InitMasks(bob
->BobVSprite
);
206 Check for roach overlapping specified rectangle.
209 RoachOverRect(roach
, rx
, ry
, x
, y
, width
, height
)
218 if (rx
>= (x
+ width
)) return 0;
219 if ((rx
+ roach
->rm
->width
) <= x
) return 0;
220 if (ry
>= (y
+ height
)) return 0;
221 if ((ry
+ roach
->rm
->height
) <= y
) return 0;
227 Check for roach completely in specified rectangle.
230 RoachInRect(roach
, rx
, ry
, x
, y
, width
, height
)
239 if (rx
< x
) return 0;
240 if ((rx
+ roach
->rm
->width
) > (x
+ width
)) return 0;
241 if (ry
< y
) return 0;
242 if ((ry
+ roach
->rm
->height
) > (y
+ height
)) return 0;
257 #ifdef CHECK_COLLISION
262 roach
= &roaches
[rx
];
263 newX
= roach
->x
+ (roachSpeed
* roach
->rm
->cosine
);
264 newY
= roach
->y
- (roachSpeed
* roach
->rm
->sine
);
266 if (RoachInRect(roach
, (int)newX
, (int)newY
,
267 xoffset
, yoffset
, display_width
, display_height
)) {
271 roach
->bob
->BobVSprite
->X
= roach
->x
;
272 roach
->bob
->BobVSprite
->Y
= roach
->y
;
274 if (roach
->steps
-- <= 0) {
276 roach
->steps
= RandInt(200);
279 #ifdef CHECK_COLLISION
283 for (ii
=rx
+1; ii
<curRoaches
; ii
++) {
286 if (r2
->hidden
) /* so roach will not turn before window */
287 continue; /* if there are already others hiding */
289 if (RoachOverRect(roach
, (int)newX
, (int)newY
,
290 r2
->intX
, r2
->intY
, r2
->rm
->width
, r2
->rm
->height
)) {
299 roach
->steps
= RandInt(100);
312 if (roach
->turnLeft
) {
313 roach
->index
+= (RandInt(70) / 10) + 1;
314 if (roach
->index
>= ROACH_HEADINGS
)
315 roach
->index
-= ROACH_HEADINGS
;
318 roach
->index
-= (RandInt(70) / 10) + 1;
319 if (roach
->index
< 0)
320 roach
->index
+= ROACH_HEADINGS
;
323 roach
->rm
= &roachPix
[roach
->index
];
325 roach
->bob
->BobVSprite
->ImageData
= (UWORD
*) roach
->rm
->roachBits
;
326 InitMasks(roach
->bob
->BobVSprite
);
331 TurnToHeading(Roach
*roach
, int index
)
335 roach
->index
= index
;
336 roach
->rm
= &roachPix
[roach
->index
];
338 roach
->bob
->BobVSprite
->ImageData
= (UWORD
*) roach
->rm
->roachBits
;
339 InitMasks(roach
->bob
->BobVSprite
);
353 int ltvis
, lbvis
, rtvis
, rbvis
, visible
;
357 for (rx
=0; rx
<curRoaches
; rx
++) {
361 * Since we don't really care for exact info but for speed,
362 * we do not call LockLayerInfo here.
364 ltvis
= (WhichLayer(LayerInfo
, r
->intX
+2, r
->intY
+13) == myLayer
);
365 lbvis
= (WhichLayer(LayerInfo
, r
->intX
+2, r
->intY
+ r
->rm
->height
-13) == myLayer
);
366 rtvis
= (WhichLayer(LayerInfo
, r
->intX
+ r
->rm
->width
-2, r
->intY
+13) == myLayer
);
367 rbvis
= (WhichLayer(LayerInfo
, r
->intX
+ r
->rm
->width
-2, r
->intY
+ r
->rm
->height
-13) == myLayer
);
369 visible
= ltvis
+ lbvis
+ rtvis
+ rbvis
;
375 D(printf("%d becomes hidden\n", rx
))
377 else { /* At least some part is hidden */
382 if (!(rbvis
|| rtvis
)) /* right side is hidden */
384 else if (!(lbvis
|| ltvis
)) /* left side is hidden */
385 TurnToHeading(r
, 13);
386 else if (!(lbvis
|| rbvis
)) /* bottom is hidden */
387 TurnToHeading(r
, 17);
388 else if (!(ltvis
|| rtvis
)) /* top is hidden */
395 TurnToHeading(r
, 21);
397 TurnToHeading(r
, 15);
404 else { /* Hidden roach becomes visible */
407 r
->turnLeft
= RandInt(100) >= 50;
425 * checkSquish - Check to see if we have to squish any roaches.
433 BOOL checksquish
= FALSE
;
434 struct IntuiMessage
*imsg
;
437 while ((imsg
= (struct IntuiMessage
*) GetMsg(roachWindow
->UserPort
))) {
438 if (imsg
->Class
== IDCMP_MOUSEBUTTONS
&& imsg
->Code
== SELECTDOWN
) {
444 D(printf("Received IDCMP %d\n", imsg
->Class
))
446 ReplyMsg((struct Message
*) imsg
);
450 for (rx
=0; rx
<curRoaches
; rx
++) {
454 x
< (r
->intX
+ r
->rm
->width
) &&
456 y
< (r
->intY
+ r
->rm
->height
)) {
459 * Roach r has been squished!
461 RemIBob(r
->bob
, rp
, vp
); /* Remove Bob from GEL-system */
464 * This causes the next SortGList() to
465 * access illegal memory. WHY?
467 * freeBob(r->bob, RasDepth); / Free its Bob struct /
469 * Then change FreeAllRoaches(): for(.. <curRoaches...)
473 BltTemplate((PLANEPTR
) squish
.roachBits
, 0, (squish
.height
/ 8),
474 rp
, r
->intX
, r
->intY
, r
->rm
->width
, r
->rm
->height
);
476 for (i
= rx
; i
< curRoaches
- 1; i
++) {
477 roaches
[i
] = roaches
[i
+ 1];
479 roaches
[curRoaches
-1].bob
= tmpbob
;
489 /**********************************************************************/
491 /* Amiga Animation functions */
493 /**********************************************************************/
498 #ifdef ROACHNUMBERING
508 #ifdef ROACHNUMBERING
509 for (i
=0; i
< maxRoaches
; i
++) {
512 sprintf(number
, "%2d", i
);
513 Move(rp
, r
->intX
+ 10, r
->intY
+10);
526 for (rx
=0; rx
<curRoaches
; rx
++) {
527 roach
= &roaches
[rx
];
528 if (!roach
->hidden
) {
530 roach
->intX
= roach
->x
;
531 roach
->intY
= roach
->y
;
538 MakeBOBFromData(char *data
, UWORD width
, UWORD height
)
543 newbob
.nb_Image
= (UWORD
*) data
;
544 newbob
.nb_WordWidth
= (width
+ 15) / 16;
545 newbob
.nb_LineHeight
= height
;
546 newbob
.nb_ImageDepth
= ROACH_DEPTH
;
547 newbob
.nb_PlanePick
= 1;
548 newbob
.nb_PlaneOnOff
= 0;
549 newbob
.nb_BFlags
= SAVEBACK
+OVERLAY
;
551 newbob
.nb_RasDepth
= RasDepth
;
554 newbob
.nb_HitMask
= 0;
555 newbob
.nb_MeMask
= 0;
557 bob
= makeBob(&newbob
); /* from animtools */
564 * X-Bitmap data stores bits reversed: the leftmost bit in the bitmap is
565 * the least significant bit in the character.
566 * So we have to mirror them.
575 for (rx
=0; rx
<ROACH_HEADINGS
; rx
++) {
580 for (i
=0; i
< (rm
->height
* (rm
->width
/ 8)); i
++) {
581 a
[i
] = ReverseBits
[a
[i
]];
585 a
= squish
.roachBits
;
586 for (i
=0; i
< (squish
.height
* (squish
.width
/ 8)); i
++) {
587 a
[i
] = ReverseBits
[a
[i
]];
593 void SetupAnimation()
600 GelsInfo
= setupGelSys(rp
, 0);
601 if (GelsInfo
== NULL
)
602 Die("InitGELSystem() failed.\n");
607 Initialize sine & cosine in RoachMaps array.
609 for (ax
=0; ax
<360; ax
+=ROACH_ANGLE
) {
610 rx
= ax
/ ROACH_ANGLE
;
611 angle
= rx
* 0.261799387799;
613 rm
->sine
= sin(angle
);
614 rm
->cosine
= cos(angle
);
620 roaches
= (Roach
*) AllocMem(sizeof(Roach
) * maxRoaches
, MEMF_CLEAR
);
622 Die("Out of memory.\n");
624 while (curRoaches
< maxRoaches
)
625 AddRoach(); /* initializes "roaches[curRoaches]" */
633 * Remove all remaining roaches from the GEL-system
640 * All roaches >= curRoaches have already been removed by checkSquish
642 for (i
=0; i
<curRoaches
; i
++) {
643 RemBob(roaches
[i
].bob
);
649 void FreeAllRoaches(void)
653 for (i
=0; i
< maxRoaches
; i
++) {
654 if (roaches
[i
].bob
) {
655 freeBob(roaches
[i
].bob
, RasDepth
);
659 FreeMem(roaches
, sizeof(Roach
) * maxRoaches
);
663 /**********************************************************************/
665 /* Own support functions */
667 /**********************************************************************/
673 * Opens and returns backdrop window on screen or NULL.
674 * Screen must be locked.
677 FindRootWindow(struct Screen
*screen
)
679 struct Window
*win
= NULL
;
682 win
= screen
->FirstWindow
;
685 if (win
->Flags
& WFLG_BACKDROP
)
687 win
= win
->NextWindow
;
689 #endif /* USE_WB_WINDOW */
692 * Open a backdrop if none available
695 roachWindow
= OpenWindowTagList(NULL
, roachWindowTags
); /* global */
700 Die("Could not open window.\n");
707 * Generate a command line from Tooltypes and supply it to rda.
710 Tooltypes2RDArgs(struct RDArgs
*rda
, int argc
, char **argv
)
712 char *cmdline
, tmpbuffer
[MAXCMDLINE
];
716 if ((ttarray
= ArgArrayInit(argc
, (STRPTR
*)argv
))) {
721 for ( ; ttarray
&& tt
; ttarray
++, tt
= *ttarray
) {
722 D(printf("%s\n", tt
))
724 if ( isalnum(*tt
) ) {
726 * Idea: If there is a ' ' in ttarray, quote the argument
728 strncat(tmpbuffer
, tt
, MAXCMDLINE
);
729 strncat(tmpbuffer
, " ", MAXCMDLINE
);
731 else { /* Skip commented tooltypes */
732 D(printf("Skipping `%s'\n", ttarray
))
736 strncat(tmpbuffer
, "\n", MAXCMDLINE
); /* to make ReadArgs happy */
737 linelen
= strlen(tmpbuffer
);
740 cmdline
= AllocMem(linelen
, MEMF_CLEAR
);
741 if (cmdline
== NULL
) {
742 Die("No memory for cmdline.\n");
744 strncpy(cmdline
, tmpbuffer
, linelen
);
746 rda
->RDA_Source
.CS_Buffer
= cmdline
;
747 rda
->RDA_Source
.CS_Length
= linelen
;
749 D(printf("Built cmdline:\n%s\n", cmdline
))
759 void Initialize(int argc
, char **argv
)
761 struct Window
*rootWin
; /* the window we will draw in */
764 * All libraries are opened by SAS/C autoinitialization (hopefully)
767 RDArgs
.RDA_ExtHelp
= ExtendedHelp
;
769 if (argc
== 0) { /* we were started from Workbench */
770 Tooltypes2RDArgs(&RDArgs
, argc
, argv
);
773 if (ReadArgs(TEMPLATE
, opts
, &RDArgs
) == NULL
) {
774 PrintFault(IoErr(), NULL
);
775 printf("Your options are not valid.\n");
776 CleanExit(RETURN_WARN
);
779 if (opts
[OPT_HELP
]) {
780 printf("%s", ExtendedHelp
);
781 FreeArgs(&RDArgs
); /* don't forget! */
782 CleanExit(RETURN_OK
);
785 if (opts
[OPT_ROACHES
]) {
786 maxRoaches
= * (ULONG
*) opts
[OPT_ROACHES
];
788 if (maxRoaches
> ROACH_LIMIT
) {
789 printf("Won't use more than %d roaches.\n", ROACH_LIMIT
);
790 maxRoaches
= ROACH_LIMIT
;
792 if (maxRoaches
< 1) {
793 maxRoaches
= ROACH_NUM
;
795 if (opts
[OPT_SPEED
]) {
796 roachSpeed
= * (ULONG
*) opts
[OPT_SPEED
];
799 roachSpeed
= ROACH_SPEED
;
801 if (opts
[OPT_SQUISH
]) {
805 if (opts
[OPT_SCREEN
]) {
806 strncpy(PubScreen
, (char *) opts
[OPT_SCREEN
], MAXNAMESIZE
);
809 strcpy(PubScreen
, "Workbench");
813 Screen
= LockPubScreen(PubScreen
);
814 if (Screen
== NULL
) {
815 printf("Cannot lock screen `%s', using default screen.\n", PubScreen
);
816 Screen
= LockPubScreen(NULL
);
818 Die("No screen available.\n");
821 ScreenToFront(Screen
);
823 userWindow
= OpenWindowTagList(NULL
, userWindowTags
); /* global */
824 if (userWindow
== NULL
)
825 Die("Could not open user window.\n");
827 rootWin
= FindRootWindow(Screen
);
829 Die("Cannot find root window.\n");
832 yoffset
= Screen
->BarHeight
;
834 display_width
= rootWin
->Width
;
835 display_height
= rootWin
->Height
;
841 vp
= &(rootWin
->WScreen
->ViewPort
);
842 RasDepth
= rp
->BitMap
->Depth
;
844 LayerInfo
= &(Screen
->LayerInfo
);
847 RangeSeed
= -VBeamPos(); /* Seed generator for amiga.lib */
851 void CleanExit(LONG ReturnCode
)
857 cleanupGelSys(GelsInfo
, rp
);
862 if (RDArgs
.RDA_Source
.CS_Buffer
)
863 FreeMem(RDArgs
.RDA_Source
.CS_Buffer
, RDArgs
.RDA_Source
.CS_Length
);
866 CloseWindow(roachWindow
);
869 CloseWindow(userWindow
);
872 UnlockPubScreen(NULL
, Screen
);
878 /* --------------------------------------------------------------
879 Die on fatal error. Prints out info text, then exits gracefully.
880 -------------------------------------------------------------- */
881 void Die(const UBYTE
* msg
)
884 CleanExit(RETURN_FAIL
);
888 BOOL
KeepRunning(void)
890 struct IntuiMessage
*imsg
;
893 if (curRoaches
<= 0) {
897 /* Check for CTRL-C */
898 if (SetSignal(0L, SIGBREAKF_CTRL_C
) & SIGBREAKF_CTRL_C
) {
902 /* Check for CLOSEWINDOW */
903 while ((imsg
= (struct IntuiMessage
*) GetMsg(userWindow
->UserPort
))) {
904 if (imsg
->Class
== IDCMP_CLOSEWINDOW
) {
907 ReplyMsg((struct Message
*) imsg
);
913 struct Library
* LayersBase
;
914 struct GfxBase
* GfxBase
;
915 struct Library
* IconBase
;
916 struct IntuitionBase
* IntuitionBase
;
920 LayersBase
= OpenLibrary("layers.library",0);
921 GfxBase
= (struct GfxBase
*)OpenLibrary("graphics.library",0);
922 IconBase
= OpenLibrary("icon.library",0);
923 IntuitionBase
= (struct IntuitionBase
*)OpenLibrary("intuition.library",0);
925 if (!LayersBase
|| !GfxBase
|| !IconBase
|| !IntuitionBase
)
933 if (LayersBase
) CloseLibrary(LayersBase
);
934 if (GfxBase
) CloseLibrary((struct Library
*)GfxBase
);
935 if (IconBase
) CloseLibrary(IconBase
);
936 if (IntuitionBase
) CloseLibrary((struct Library
*)IntuitionBase
);
940 void __chkabort(void) {}
943 main(int argc
, char **argv
)
947 if (TRUE
== openlibs())
949 Initialize(argc
, argv
);
955 while (KeepRunning()) {
964 nVis
= MarkHiddenRoaches();
972 CleanExit(RETURN_OK
);