home *** CD-ROM | disk | FTP | other *** search
- /*
- * MOON ROCKS by Alan Bland. This is an example game using the
- * GameSmith Development System. You are free to use portions of
- * this source code for any purpose whatsoever. This isn't
- * necessarily the best way to use GDS for this type of game,
- * but it shows usage of many of the components of GDS (anims,
- * anim complexes, sounds, scrolling background, multiple viewports,
- * RastPort usage, background collision detection).
- *
- * This game won't work on an OCS Amiga because of the large
- * scrolling superbitmap. It may also require 1 meg of chip ram.
- *
- * The elvis animation is based on the "tiny elvis" public domain
- * screen hack for Microsoft Windows. I changed it around quite
- * a bit to reduce the color palette and to make different dancing
- * motions from the original.
- *
- * Call CYBERMIGA BBS at 1-303-939-9923. Lots of Amiga files!
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <fcntl.h>
- #include <math.h>
- #include <intuition/intuition.h>
- #include <exec/memory.h>
- #include <exec/types.h>
- #include <graphics/gfx.h>
- #include <graphics/gfxbase.h>
-
- #include <clib/exec_protos.h>
- #include <clib/graphics_protos.h>
- #include <clib/intuition_protos.h>
-
- #include "GameSmith:GameSmith.h"
- #include "GameSmith:include/libraries/libptrs.h"
- #include "GameSmith:include/proto/all_regargs.h"
-
- /* header file for anim complexes */
- #include "lc.h"
- #include "rs.h"
-
- #define DDEPTH 3
- #define NUM_COLORS 8
-
- #define VP2_HEIGHT 19
- #define VP2_DEPTH 3
- #define VP2_NUM_COLORS 8
-
- #define DWIDTH 320
- #define DHEIGHT (200-VP2_HEIGHT-3)
- #define DISP_MODE 0
-
- #define X_SCROLLPOS (DWIDTH/3)
- #define Y_SCROLLTOP (DHEIGHT/4)
- #define Y_SCROLLBOT (DHEIGHT/2)
-
- /* this defines the vertical position below which the spacecraft
- * can collide with background objects. see main loop comments.
- */
- #define GROUND_THRESHOLD (bmheight-52)
-
- /* this is how close (pixels) we must land to the target to win the game */
- #define CLOSE_ENOUGH 250
-
- #define MAX_FUEL 3000
- #define LOW_FUEL 300
-
- /* physical constants */
- #define MAX_ALTITUDE 70000.0
- #define MAX_RANGE 50000.0
- #define GRAVITY 5.0
- #define THRUST 10.0
- #define SAFE_SPEED 200.0
-
- /* To be strictly accurate, I think this should be 60 for NTSC, 50 for PAL */
- #define TICKS_PER_SEC 60
-
- /* joystick responsiveness - set to 0 for fastest */
- #define JOY_INTERVAL 3
-
- /* how often to animate the rock star */
- #define DANCE_DELAY 5
- unsigned char time_to_dance;
- short dance_time;
- unsigned char rockstar_visible; /* is he visible? */
- unsigned long rockstar_time; /* next time that he changes animation */
- unsigned char allow_rockstar; /* allow him to materialize */
- /*
- * The VP2 bitmap has several different control panel images which we
- * scroll into view as necessary. The top image is the normal panel.
- * These constants define the scroll offset for each image.
- */
- #define VP_PAUSED VP2_HEIGHT
- #define VP_NOWHERE (VP2_HEIGHT*2)
- #define VP_VISIBLE (VP2_HEIGHT*3)
- #define VP_CRASHED (VP2_HEIGHT*4)
- #define VP_SUCCESS (VP2_HEIGHT*5)
-
-
- unsigned long lunar_cmap[NUM_COLORS];
- unsigned long vp2_cmap[VP2_NUM_COLORS];
-
- /*
- * vp is the viewport for the main viewing area.
- * vp2 is the control panel at the bottom of the screen.
- */
-
- struct gs_viewport vp2 = {
- NULL, /* ptr to next viewport */
- vp2_cmap, /* ptr to color table */
- VP2_NUM_COLORS, /* number of colors in table */
- NULL, /* ptr to user copper list */
- VP2_HEIGHT,DWIDTH,VP2_DEPTH, /* height, width, depth */
- 0,0, /* bmheight, bmwidth */
- DHEIGHT+2,0, /* top & left viewport offsets */
- 0,0, /* X & Y bitmap offsets */
- 0, /* flags */
- NULL,NULL, /* 2.xx & above compatibility stuff */
- NULL,NULL, /* bitmap pointers */
- NULL, /* future expansion */
- 0,0,0,0 /* display clip (use nominal) */
- };
-
- struct gs_viewport vp = {
- &vp2, /* ptr to next viewport */
- lunar_cmap, /* ptr to color table */
- NUM_COLORS, /* number of colors in table */
- NULL, /* ptr to user copper list */
- DHEIGHT,DWIDTH,DDEPTH, /* height, width, depth */
- 0,0, /* bmheight, bmwidth */
- 0,0, /* top & left viewport offsets */
- 0,0, /* X & Y bitmap offsets */
- 0, /* flags */
- NULL,NULL, /* 2.xx & above compatibility stuff */
- NULL,NULL, /* bitmap pointers */
- NULL, /* future expansion */
- 0,0,0,0 /* display clip (use nominal) */
- };
-
- struct display_struct lunar_display = {
- NULL, /* ptr to previous display view */
- NULL,NULL, /* 2.xx & above compatibility stuff */
- 0,0, /* X and Y display offsets (1.3 style) */
- DISP_MODE, /* display mode ID */
- 4,4, /* sprite priorities */
- GSV_DOUBLE|GSV_SCROLLABLE, /* flags (double buffered, scrollable) */
- &vp, /* ptr to 1st viewport */
- NULL /* future expansion */
- };
-
- struct anim_cplx *lem; /* the spacecraft anim complex */
- struct anim_cplx *rockstar; /* the rock star anim complex */
- struct display_struct *display; /* points at lunar_display if it got created ok */
- struct Interrupt *scroller=NULL; /* interrupt handler for smooth scrolling */
- int dlist=-1; /* display list used with anim system */
- int bmwidth;
- int bmheight;
- struct RastPort rp; /* RastPort for writing text to the control panel */
- struct BitMap *cp_bitmaps[2]; /* need to double-buffer bitmaps for RastPort */
- struct TextAttr sysfont = { /* control panel will be topaz.8 */
- "topaz.font", 8, 0, 0
- };
- struct TextFont *myfont;
-
- short elapsed_mins;
- short elapsed_secs;
- short elapsed_ticks;
-
- /*
- * The MED module uses channels 0 and 1. Sound effects are on 2 and 3
- * except for the PING sound, which is only played without music so it's
- * on one of the music channels.
- */
- #include "libproto.h"
- struct MMD0 *tune;
- struct Library *MEDPlayerBase;
-
- /*
- * structures and channel assignments for each sound.
- */
- #define THRUST_CHANNEL CHANNEL2
- #define WHOOP_CHANNEL CHANNEL3
- #define PING_CHANNEL CHANNEL1
- #define FILL_CHANNEL CHANNEL3
- #define KABOOM_CHANNEL CHANNEL2
- #define LANDED_CHANNEL CHANNEL3
-
- struct sound_struct thrust;
- struct sound_struct whoop;
- struct sound_struct kaboom;
- struct sound_struct landed;
- struct sound_struct ping;
- struct sound_struct fill;
-
- /* the "lc" anim complex contains zillions of short anims showing the
- spacecraft at various rotation angles (increments of 15 degrees),
- with and without flames. the "lc_flame" array lists the anims with
- flames in clockwise rotation order. "lc_noflame" lists the anims
- without flames. */
-
- #define LC_ANIM_COUNT 24
-
- short lc_flame[LC_ANIM_COUNT] = {
- FLAME00, FLAME15, FLAME30, FLAME45, FLAME60, FLAME75,
- FLAME90, FLAME105, FLAME120, FLAME135, FLAME150, FLAME165,
- FLAME180, FLAME195, FLAME210, FLAME225, FLAME240, FLAME255,
- FLAME270, FLAME285, FLAME300, FLAME315, FLAME330, FLAME345
- };
- short lc_noflame[LC_ANIM_COUNT] = {
- LEM00, LEM15, LEM30, LEM45, LEM60, LEM75,
- LEM90, LEM105, LEM120, LEM135, LEM150, LEM165,
- LEM180, LEM195, LEM210, LEM225, LEM240, LEM255,
- LEM270, LEM285, LEM300, LEM315, LEM330, LEM345
- };
-
- /* sines and cosines are pre-computed for each 15 degree rotational
- position. this makes the game fast enough to run on an old
- 68000 Amiga without a math chip. */
-
- double sinval[LC_ANIM_COUNT] = {
- -1.000000, -0.966168, -0.866519, -0.707840, -0.500941, -0.259916,
- 0.000000, 0.258771, 0.499914, 0.707002, 0.865927, 0.965862,
- 1.000000, 0.966015, 0.866223, 0.707421, 0.500428, 0.259344,
- 0.000593, -0.258199, -0.499401, -0.706583, -0.865630, -0.965708
- };
-
- double cosval[LC_ANIM_COUNT] = {
- -0.000889, 0.257913, 0.499144, 0.706373, 0.865482, 0.965631,
- 1.000000, 0.965939, 0.866075, 0.707212, 0.500171, 0.259058,
- 0.000296, -0.258485, -0.499658, -0.706792, -0.865778, -0.965785,
- -1.000000, -0.966092, -0.866371, -0.707630, -0.500684, -0.259630
- };
-
-
- /* The "craft" structure defines the current physical attributes of
- the spacecraft. */
-
- struct {
- int fuel; /* fuel remaining */
- int index; /* array index into lc_flame/lc_noflame which indicates
- the current rotation of the spacecraft */
- int collision; /* did the craft collide with something */
- double altitude; /* altitude above surface */
- double range; /* position along surface */
- double vel_x; /* velocity x component */
- double vel_y; /* velocity y component */
- double vel; /* velocity vector */
- double prev_vel; /* previous velocity - need for landing speed */
- } craft;
-
- /*
- * calculate the new position of the spacecraft. "burn" is 1 if we are
- * currently burning fuel, 0 if not. we maintain a coordinate system
- * using altitude and range, and convert to screen x,y coordinates.
- * return value indicates whether we actually burned any fuel.
- * you could probably make this function faster...
- */
-
- int compute_pos(int burn)
- {
- double v0;
- double x0;
- double accel_x;
- double accel_y;
- int did_burn;
-
- /* burn some fuel if there's any left */
- if (burn && craft.fuel) {
- accel_x = (THRUST - GRAVITY) * cosval[craft.index];
- accel_y = -(THRUST - GRAVITY) * sinval[craft.index];
- --craft.fuel;
- did_burn = 1;
- } else {
- accel_x = 0;
- accel_y = -GRAVITY;
- did_burn = 0;
- }
-
- v0 = craft.vel_x;
- craft.vel_x = v0 + accel_x;
- x0 = craft.range;
- craft.range = x0 + v0 + (accel_x/2);
- if (craft.range < 0) {
- /* bounce off the edge of the moon (lose some velocity) */
- craft.range = 0;
- craft.vel_x = -craft.vel_x/3;
- accel_x = -accel_x/3;
- }
- else if (craft.range >= MAX_RANGE) {
- craft.range = MAX_RANGE;
- craft.vel_x = -craft.vel_x/3;
- accel_x = -accel_x/3;
- }
-
- v0 = craft.vel_y;
- craft.vel_y = v0 + accel_y;
- x0 = craft.altitude;
- craft.altitude = x0 + v0 + (accel_y/2);
- if (craft.altitude < 0) {
- craft.altitude = 0;
- craft.vel_y = 0;
- accel_y = 0;
- }
- else if (craft.altitude >= MAX_ALTITUDE) {
- craft.altitude = MAX_ALTITUDE;
- craft.vel_y = 0;
- }
-
- /* calculate velocity vector */
- craft.prev_vel = craft.vel;
- craft.vel = sqrt(craft.vel_x * craft.vel_x + craft.vel_y * craft.vel_y);
-
- /* convert lunar position to bitmap coordinates */
- lem->anim->x = craft.range * bmwidth / MAX_RANGE;
- lem->anim->y = (bmheight-30) - (craft.altitude * (bmheight-30) / MAX_ALTITUDE);
-
- return did_burn;
- }
-
- /*
- * collision handler for craft-to-background checks. the pallete has been
- * created such that the background colors of interest are in the third
- * bitplane (colors 4,5,6,7). we want to ignore the mountains but collide
- * with the rocks on the ground, so the collision handler is enabled only
- * below a certain altitude. see the main loop for where we enable and
- * disable the collision handler.
- */
- void grounded(struct anim_struct *anim, struct coll_bg_struct *point, int color)
- {
- craft.collision = color;
- }
-
- /*
- * show current stats on the control panel
- */
- void show_stats(void)
- {
- char cpbuf[30];
-
- /* update current information on the control panel */
- SetAPen(&rp, 3); /* green */
-
- /* divide altitude and velocity by 10 for a more reasonable output */
- sprintf(cpbuf, "%05d", (int)craft.altitude / 10);
- Move(&rp, 22, 12);
- Text(&rp, cpbuf, 5);
- sprintf(cpbuf, "%05d", (int)craft.vel / 10);
- Move(&rp, 85, 12);
- Text(&rp, cpbuf, 5);
- if (craft.fuel <= LOW_FUEL) {
- SetAPen(&rp, 2); /* red */
- }
- sprintf(cpbuf, "%05d", (int)craft.fuel);
- Move(&rp, 153, 12);
- Text(&rp, cpbuf, 5);
-
- SetAPen(&rp, 3); /* green */
- sprintf(cpbuf, "%02d:%02d", elapsed_mins, elapsed_secs);
- Move(&rp, 219, 12);
- Text(&rp, cpbuf, 5);
- }
-
- /*
- * VB interrupt handler: scroll the display when the spacecraft
- * gets near one of the edges.
- */
-
- unsigned long vbcounter;
-
- void __interrupt __saveds scroll(void)
- {
- int dx, dy;
-
- ++vbcounter;
-
- /* keep track of elapsed time */
- if (++elapsed_ticks == TICKS_PER_SEC) {
- elapsed_ticks = 0;
- if (++elapsed_secs == 60) {
- elapsed_secs = 0;
- ++elapsed_mins;
- }
- }
-
- /* keep track of when it's ok for the rock star to dance */
- if (--dance_time <= 0) {
- time_to_dance = 1;
- dance_time = DANCE_DELAY;
- }
-
- /* don't scroll if showing the explosion */
- if (lem->seq == BOOM) {
- return;
- }
-
- if (lem->anim->x < vp.xoff + X_SCROLLPOS) {
- dx = vp.xoff + X_SCROLLPOS - lem->anim->x;
- } else if (lem->anim->x > vp.xoff + DWIDTH - X_SCROLLPOS) {
- dx = vp.xoff + DWIDTH - X_SCROLLPOS - lem->anim->x;
- } else {
- dx = 0;
- }
-
- if (lem->anim->y < vp.yoff + Y_SCROLLTOP) {
- dy = vp.yoff + Y_SCROLLTOP - lem->anim->y;
- } else if (lem->anim->y > vp.yoff + DHEIGHT - Y_SCROLLBOT) {
- dy = vp.yoff + DHEIGHT - Y_SCROLLBOT - lem->anim->y;
- } else {
- dy = 0;
- }
-
- if (dx != 0 || dy != 0) {
- gs_scroll_vp(display, 0, -dx, -dy, 1);
- }
- }
-
-
- /*
- * delay specified number of vb ticks, sync with display
- */
- void mydelay(int vbticks)
- {
- int n = vbcounter + vbticks;
- while (vbcounter < n);
- while (display->flags & GSV_FLIP); /* while page not flipped yet */
- }
-
- /*
- * display an error message (we should never need this)
- */
-
- struct IntuiText hdrtext = { 1,0,JAM2,10,16,NULL,NULL,NULL };
- struct IntuiText fataltext = { 2,0,JAM2,10,32,NULL,NULL,&hdrtext };
- struct IntuiText canceltext = { 1,0,JAM2,7,3,NULL,"Cancel",NULL };
-
- void myerror(char *text)
- {
- hdrtext.IText = "Bad news from the moon...";
- fataltext.IText = text;
- AutoRequest(NULL, &fataltext, NULL, &canceltext, 0, 0, 600, 90);
- }
-
- /*
- * cleanup all resources and exit
- */
-
- void cleanup(void)
- {
- gs_close_sound();
- gs_free_sound(&thrust);
- gs_free_sound(&whoop);
- gs_free_sound(&ping);
- gs_free_sound(&fill);
- gs_free_sound(&kaboom);
- gs_free_sound(&landed);
-
- if (dlist > -1) _gs_free_display_list(dlist);
- if (scroller) _gs_remove_vb_server(scroller);
- if (lem) gs_free_cplx(lem, 1);
- if (rockstar) gs_free_cplx(rockstar, 1);
- if (display) gs_remove_display(display);
- /* since we allocated our own bitmaps we must free them */
- if (vp.bitmap1) gs_free_bitmap(vp.bitmap1);
- if (vp.bitmap2) gs_free_bitmap(vp.bitmap2);
- if (vp2.bitmap1) gs_free_bitmap(vp2.bitmap1);
- if (vp2.bitmap2) gs_free_bitmap(vp2.bitmap2);
-
- /* free up MED stuff */
- if (tune) {
- StopPlayer();
- UnLoadModule(tune);
- FreePlayer();
- }
- if (MEDPlayerBase) CloseLibrary(MEDPlayerBase);
-
- gs_close_libs();
- exit(0);
- }
-
-
- /*
- * setup all game data
- */
-
- int setup(void)
- {
- struct anim_load_struct load = {
- "lc.cplx", 0, 0, 0, 0, 8, 0, 1, ANIMLOAD_NOCOLOR
- };
- struct anim_load_struct loadrs = {
- "rs.cplx", 0, 0, 0, 0, 8, 0, 1, ANIMLOAD_NOCOLOR
- };
- struct loadILBM_struct loadimg = {
- "landscape.iff", 0, 0, lunar_cmap, NUM_COLORS, 0, 0, 0, 0, 0, 0, 0,
- ILBM_COLOR | ILBM_ALLOC2, 0xff, 0xff
- };
- struct loadILBM_struct loadimg2 = {
- "panel.iff", 0, 0, vp2_cmap, VP2_NUM_COLORS, 0, 0, 0, 0, 0, 0, 0,
- ILBM_COLOR | ILBM_ALLOC2, 0xff, 0xff
- };
-
- int result;
- int page;
-
- /* open amiga libraries */
- if (gs_open_libs(DOS|GRAPHICS|INTUITION|MATHDBLB|MATHDBLT|MATHTRANS,0)) {
- exit(1);
- }
-
- /* Open the MEDplayer library */
- MEDPlayerBase=(struct Library *)OpenLibrary("medplayer.library",0);
- if (!MEDPlayerBase) {
- myerror("Need medplayer.library");
- return -1;
- }
-
- /* Load the mod */
- tune = LoadModule("mod.MoonRocks");
- if (!tune) {
- myerror("Couldn't load mod.MoonRocks");
- return -1;
- }
-
- /* Initialize the MED player */
- if (GetPlayer(0)) {
- myerror("Can't Initialize MED player!");
- }
-
- /*
- * load the lunar landscape. this creates two superbitmaps for the
- * double-buffered scrolling viewport, and fills in the color table
- * used by all game objects.
- */
- result = gs_loadILBM(&loadimg);
- if (result) {
- myerror(loadimg.file);
- return result;
- }
-
- /* viewport will use the bitmaps just allocated */
- vp.bitmap1 = loadimg.bitmap1;
- vp.bitmap2 = loadimg.bitmap2;
- bmwidth=vp.bitmap1->BytesPerRow*8;
- bmheight=vp.bitmap1->Rows;
-
- /* load the control panel image */
- result = gs_loadILBM(&loadimg2);
- if (result) {
- myerror(loadimg.file);
- return result;
- }
- vp2.bitmap1 = loadimg2.bitmap1;
- vp2.bitmap2 = loadimg2.bitmap2;
- cp_bitmaps[0] = vp2.bitmap1;
- cp_bitmaps[1] = vp2.bitmap2;
-
- /* control panel needs a RastPort so we can draw text to it */
- InitRastPort(&rp);
- rp.BitMap = vp2.bitmap1;
- SetDrMd(&rp, JAM2);
- SetBPen(&rp, 0); /* black */
-
- /* force topaz.8 in the control panel */
- myfont = OpenFont(&sysfont);
- if (!myfont) {
- myerror("Can't open topaz.8 font");
- return -1;
- }
- SetFont(&rp, myfont);
-
- /* load the spacecraft anim */
- if (result = gs_load_anim(&load)) {
- myerror(load.filename);
- return result;
- }
-
- /* get pointer to the loaded anim */
- lem = load.anim_ptr.cplx;
-
- /* load the rock star anim */
- if (result = gs_load_anim(&loadrs)) {
- myerror(loadrs.filename);
- return result;
- }
-
- /* get pointer to the loaded anim */
- rockstar = loadrs.anim_ptr.cplx;
-
- /* create the display */
- #ifdef NTSC_MONITOR_ID
- if (GfxBase->LibNode.lib_Version >= 36) /* if WB 2.0 or higher */
- { /* this defeats mode promotion on AGA machines */
- if (ModeNotAvailable(NTSC_MONITOR_ID))
- {
- lunar_display.modes = PAL_MONITOR_ID;
- }
- else
- {
- lunar_display.modes = NTSC_MONITOR_ID;
- }
- }
- #endif
- result = gs_create_display(&lunar_display);
- if (result) {
- myerror("gs_create_display failed");
- return result;
- }
- display = &lunar_display;
-
- if ((dlist=_gs_get_display_list()) < 0) {
- myerror("gs_get_display_list failed");
- return result;
- }
-
- /* perform other anim initialization */
- gs_init_anim(dlist,display->vp->bitmap1, display->vp->bitmap2, NULL);
- gs_set_anim_bounds(dlist,0, 0, bmwidth-1, bmheight-1);
- gs_random(0);
-
- /* setup the sound system and load the sounds */
- if (gs_open_sound(0,1,-10,2560)) {
- myerror("gs_open_sound failed");
- return -1;
- }
-
- /* sound of the thrusters */
- thrust.flags = SND_FAST;
- if (result=gs_load_iff_sound(&thrust,0,"thrust.snd")) {
- myerror("cannot load thrust.snd");
- return result;
- }
- thrust.repeat = 0; /* loop forever */
-
- /* low fuel alert */
- whoop.flags = SND_FAST;
- if (result=gs_load_iff_sound(&whoop,0,"whoop.snd")) {
- myerror("cannot load whoop.snd");
- return result;
- }
- whoop.repeat = 0; /* loop forever */
-
- /* a nice explosion */
- kaboom.flags = SND_FAST;
- if (result=gs_load_raw_sound(&kaboom,"kaboom.snd")) {
- myerror("cannot load kaboom.snd");
- return result;
- }
-
- /* startrek bridge sound */
- ping.flags = SND_FAST;
- if (result=gs_load_raw_sound(&ping,"ping.snd")) {
- myerror("cannot load ping.snd");
- return result;
- }
- ping.repeat = 0; /* loop forever */
-
- /* sound played when filling the gas tank */
- fill.flags = SND_FAST;
- if (result=gs_load_iff_sound(&fill,0,"fill.snd")) {
- myerror("cannot load fill.snd");
- return result;
- }
- fill.repeat = 0; /* loop forever */
-
- /* sound played when landing is successful */
- landed.flags = SND_FAST;
- if (result=gs_load_iff_sound(&landed,0,"landed.snd")) {
- myerror("cannot load landed.snd");
- return result;
- }
-
- /* add the anims to the display */
- if (result = gs_add_anim_cplx(dlist,lem, 0, 0, lc_noflame[craft.index], 0)) {
- myerror("gs_add_anim_cplx failed");
- return result;
- }
- if (result = gs_add_anim_cplx(dlist,rockstar, 0, 0, DANCE1, 0)) {
- myerror("gs_add_anim_cplx failed");
- return result;
- }
-
- gs_draw_anims(dlist);
- page = gs_next_anim_page(dlist);
- rp.BitMap = cp_bitmaps[page];
-
- /* even more anim initialization */
- gs_show_display(display,1);
- gs_flip_display(display,1);
-
- /* setup the scrolling routine */
- scroller = gs_add_vb_server(&scroll, 0);
- if (!scroller) {
- myerror("gs_add_vb_server failed");
- return -5;
- }
-
- /* setup collision handler for things on the ground */
- gs_set_collision_bg(dlist, grounded);
-
- return 0;
- }
-
- /*
- * flip to the next display page, making sure that the
- * rastport bitmap for the control panel is in sync.
- */
- void flipper(void)
- {
- int page;
-
- gs_draw_anims(dlist);
- page = gs_next_anim_page(dlist);
- rp.BitMap = cp_bitmaps[page];
- gs_flip_display(display,1);
- }
-
- /*
- * Start background noise - depending on whether the rock star is
- * visible, it's either the startrek bridge sound, or some music.
- */
- void start_background_noise(void)
- {
- if (rockstar_visible) {
- /* Continue playing the mod */
- ContModule(tune);
- } else {
- gs_start_sound(&ping, PING_CHANNEL);
- }
- }
-
- /*
- * Stop whichever background noise is playing.
- */
- void stop_background_noise(void)
- {
- if (rockstar_visible) {
- /* Stop playing the mod */
- StopPlayer();
- } else {
- gs_stop_sound(PING_CHANNEL);
- }
- }
-
- /*
- * animate the dancing rock star. time_to_dance is set in the vb interrupt
- * when enough time has elapsed to do the next dance frame. rockstar_time is
- * when it's time to switch to a different dance, or when to make him
- * materialize if he's currently invisible.
- */
- void dance(void)
- {
- if (rockstar_visible) {
- /* switch to a different dance animation every once in awhile */
- if (vbcounter >= rockstar_time) {
- if (rockstar->seq == DANCE1) {
- gs_set_cplx_seq(rockstar, DANCE2, rockstar->anim->x, rockstar->anim->y);
- } else {
- gs_set_cplx_seq(rockstar, DANCE1, rockstar->anim->x, rockstar->anim->y);
- }
-
- /* switch again at a random time */
- rockstar_time = vbcounter + (gs_random(5) + 5) * TICKS_PER_SEC;
- }
- if (time_to_dance) {
- time_to_dance = 0;
- gs_anim_cplx(rockstar, rockstar->anim->x, rockstar->anim->y);
- }
- }
- else if (vbcounter >= rockstar_time && allow_rockstar) {
-
- /* time for him to materialize */
- gs_enable_cplx(rockstar);
- rockstar_visible = 1;
-
- /* he materializes in the reclining position and must stand up */
- gs_set_cplx_seq(rockstar, STANDUP, rockstar->anim->x, rockstar->anim->y);
- gs_set_cplx_cell(rockstar, 0);
-
- /* he'll start dancing in three seconds */
- rockstar_time = vbcounter + 3 * TICKS_PER_SEC;
-
- /* stop the ping and start the music he'll be dancing to */
- gs_stop_sound(PING_CHANNEL);
- PlayModule(tune);
- }
- }
-
- void show_panel(int offset)
- {
- gs_scroll_vp(display, 1, 0, offset, 1);
- }
-
- /*
- * user paused the game
- */
- void pause_game(int current_panel)
- {
- /* user pressed LMB to get here, wait for it to be released */
- while (gs_joystick(0)&JOY_BUTTON1) {}
-
- /* scroll the control panel to show the pause display */
- show_panel(VP_PAUSED - current_panel);
-
- /* wait for response */
- while (1) {
- if (gs_joystick(0) & JOY_BUTTON1) {
- /* mouse button - resume game */
- /* but wait for LMB to be released first */
- while (gs_joystick(0)&JOY_BUTTON1) {}
-
- /* scroll the control panel to return to the game display */
- show_panel(-VP_PAUSED + current_panel);
- return;
- }
- if (gs_joystick(1) & JOY_BUTTON1) {
- /* joystick button - quit game */
- Permit();
- cleanup();
- }
-
- /* dance continues even while paused */
- dance();
- mydelay(1);
- flipper();
- }
- }
-
- /*
- * landed at fuel station
- */
- void refuel(void)
- {
- stop_background_noise();
- mydelay(25);
- gs_start_sound(&fill, FILL_CHANNEL);
-
- craft.vel_x = 0;
- craft.vel_y = 0;
- craft.index = 0;
- gs_set_cplx_seq(lem, LEM00, lem->anim->x, lem->anim->y);
-
- /* fill the tank */
- while (craft.fuel < MAX_FUEL) {
-
- craft.fuel += 3;
- if (craft.fuel > MAX_FUEL) {
- craft.fuel = MAX_FUEL;
- }
-
- if (gs_joystick(0)&JOY_BUTTON1) {
-
- pause_game(0);
- }
-
- show_stats();
- gs_anim_cplx(lem, lem->anim->x, lem->anim->y);
- dance();
-
- mydelay(1);
- flipper();
- }
- gs_stop_sound(FILL_CHANNEL);
- mydelay(25);
- start_background_noise();
-
- /* wait for liftoff */
- while (1) {
-
- if (gs_joystick(0)&JOY_BUTTON1) {
-
- pause_game(0);
- }
-
- if (gs_joystick(1) & JOY_BUTTON1) {
-
- /* need to give the craft a good kick to get it away from the
- * fuel platform. otherwise the collision detection in the
- * main loop will bring us right back here.
- */
- craft.altitude += 500;
- craft.collision = 0;
- return;
- }
-
- /* continue page-flipping to show the clock ticking */
- show_stats();
- gs_anim_cplx(lem, lem->anim->x, lem->anim->y);
- dance();
- mydelay(1);
- flipper();
- }
-
- }
-
- /*
- * spacecraft crashed into something
- */
- void crash(void)
- {
- int i;
-
- stop_background_noise();
- gs_stop_sound(THRUST_CHANNEL);
- gs_stop_sound(WHOOP_CHANNEL);
- gs_start_sound(&kaboom, KABOOM_CHANNEL);
-
- /* show the crashed control panel */
- show_panel(VP_CRASHED);
-
- /* adjust anim position because explosion is bigger than craft */
- lem->anim->x -= 40;
- lem->anim->y -= 20;
- gs_set_cplx_seq(lem, BOOM, lem->anim->x, lem->anim->y);
- gs_set_cplx_cell(lem, 0);
-
- /* animate the explosion for a few seconds */
- for (i = 0; i < 90; i++) {
-
- if (gs_joystick(0)&JOY_BUTTON1) {
-
- pause_game(VP_CRASHED);
- }
- show_stats();
- gs_anim_cplx(lem, lem->anim->x, lem->anim->y);
- dance();
-
- /* explosion sequence is slower than main animation */
- mydelay(5);
- flipper();
- }
-
- /* restore the main control panel */
- show_panel(-VP_CRASHED);
-
- /* in case he appeared while we crashed... */
- stop_background_noise();
- }
-
- /*
- * successful landing. returns non-zero if won the game, else 0.
- */
- int safe_landing(void)
- {
- int panel;
- int dist;
-
- /* wait for joystick button to be released */
- while (gs_joystick(1)&JOY_BUTTON1) {}
-
- gs_stop_sound(THRUST_CHANNEL);
- craft.vel_x = 0;
- craft.vel_y = 0;
- craft.index = 0;
- gs_set_cplx_seq(lem, LEM00, lem->anim->x, lem->anim->y);
-
- /* did we land near the rock star? */
- if (rockstar_visible) {
-
- dist = abs(rockstar->anim->x - lem->anim->x);
- if (dist <= CLOSE_ENOUGH) {
-
- /* we have a winner! */
- panel = VP_SUCCESS;
- show_panel(panel);
-
- gs_stop_sound(WHOOP_CHANNEL);
-
- /* Stop playing the mod */
- StopPlayer();
- mydelay(5);
- gs_start_sound(&landed, LANDED_CHANNEL);
- mydelay(5);
-
- /* what for congrats to finish, then restart the mod */
- while (gs_sound_check() & LANDED_CHANNEL) {}
- PlayModule(tune);
-
- } else {
-
- /* didn't land close enough */
- panel = VP_VISIBLE;
- show_panel(panel);
- }
-
- } else {
- /* he's not even visible yet! */
- panel = VP_NOWHERE;
- show_panel(panel);
- }
-
-
- /* wait for liftoff */
- while (1) {
-
- if (gs_joystick(0)&JOY_BUTTON1) {
-
- pause_game(panel);
- }
-
- if (gs_joystick(1) & JOY_BUTTON1) {
-
- craft.altitude += 300;
- craft.collision = 0;
-
- /* flip back to the main control panel */
- show_panel(-panel);
-
- /* return result of landing close */
- if (panel == VP_SUCCESS) {
- stop_background_noise();
- return 1;
- } else {
- start_background_noise();
- return 0;
- }
- }
-
- show_stats();
- gs_anim_cplx(lem, lem->anim->x, lem->anim->y);
- dance();
- mydelay(5);
- flipper();
- }
- }
-
- /*
- * main program: set everything up and then play the game (duh...)
- */
-
- void main(void)
- {
- int result;
- unsigned char joy;
- int burn;
- int thrusting = 0;
- int joycount;
-
- /* setup the animation system */
- if ((result = setup()) != 0) {
- char err[60];
- sprintf(err, "setup failed (%d)", result);
- myerror(err);
- cleanup();
- }
-
- /* play multiple times until mouse button is pressed */
- Forbid();
- while (1) {
-
- /*
- * spacecraft begins with a full tank, at a random position and
- * velocity. what's really cool about this is that the scroll
- * interrupt will automatically reposition the superbitmap so
- * that the spacecraft is visible. the main loop never has
- * to care what the physical display looks like!
- */
- craft.fuel = MAX_FUEL;
- craft.altitude = MAX_ALTITUDE;
- craft.range = (gs_random(bmwidth - 200) + 100) * MAX_RANGE / bmwidth;
- craft.vel_x = gs_random(200) - 100;
- if (craft.vel_x > 0) {
- craft.index = LC_ANIM_COUNT-1;
- } else {
- craft.index = 1;
- }
- craft.vel_y = 0;
- craft.collision = 0;
- compute_pos(0);
-
- /* reset the elapsed time counter */
- elapsed_mins = 0;
- elapsed_secs = 0;
- elapsed_ticks = 0;
-
- /* place rock star at a random ground position */
- rockstar->anim->x = gs_random(bmwidth - 100) + 50;
- rockstar->anim->y = bmheight-30;
-
- /* but he's invisible for awhile */
- gs_clear_cplx(rockstar);
- rockstar_visible = 0;
- allow_rockstar = 1;
-
- /* he will materialize at a random time at least 40 seconds after
- the start of the game. */
- rockstar_time = vbcounter + (40 + gs_random(90)) * TICKS_PER_SEC;
-
- joycount = JOY_INTERVAL;
-
- show_stats();
-
- start_background_noise();
-
- /*
- * Here is the main game loop. Simply watch the joystick and move
- * the anim around appropriately. We continue in this inner loop
- * until we land near the target or we crash.
- */
- while (1) {
-
- if (gs_joystick(0)&JOY_BUTTON1) {
-
- pause_game(0);
- }
-
- /*
- * Check the joystick. Left and right will rotate the spacecraft
- * 15 degrees in either direction. Button will burn some fuel.
- */
- joy = gs_joystick(1);
-
- /*
- * Check rotational motion every JOY_INTERVAL times through this
- * loop. If we check it too often, the spacecraft rotates too
- * fast to be playable. Thrust button is checked every time.
- */
- if (--joycount <= 0) {
- joycount = JOY_INTERVAL;
-
- if (joy & JOY_RIGHT) {
- /* rotate clockwise */
- if (++craft.index == LC_ANIM_COUNT) craft.index = 0;
- } else if (joy & JOY_LEFT) {
- /* rotate counter-clockwise */
- if (--craft.index < 0) craft.index = LC_ANIM_COUNT-1;
- }
- }
-
- if (joy & JOY_BUTTON1) {
- /* calculate the next spacecraft position with full throttle */
- burn = compute_pos(1);
- } else {
- /* calculate the next spacecraft position with no throttle */
- burn = compute_pos(0);
- }
-
- /* show the spacecraft with or without flame depending on whether
- we burned any fuel */
- if (burn) {
-
- /* we burned fuel this time. show the spacecraft with flame */
- gs_set_cplx_seq(lem, lc_flame[craft.index], lem->anim->x, lem->anim->y);
- /* turn on the thrust sound if it's not already on */
- if (!thrusting) {
- thrusting = 1;
- gs_start_sound(&thrust, THRUST_CHANNEL);
- }
-
- if (craft.fuel == LOW_FUEL) {
- /* we're running on fumes! */
- gs_start_sound(&whoop, WHOOP_CHANNEL);
- } else if (craft.fuel == 0) {
- /* not even any fumes left! */
- gs_stop_sound(WHOOP_CHANNEL);
- gs_stop_sound(THRUST_CHANNEL);
- stop_background_noise();
- thrusting = 0;
- }
-
- } else {
- /* no fuel burned this time, show spacecraft without flame */
- gs_set_cplx_seq(lem, lc_noflame[craft.index], lem->anim->x, lem->anim->y);
- /* turn off thrust sound if necessary */
- if (thrusting) {
- gs_stop_sound(THRUST_CHANNEL);
- thrusting = 0;
- }
- }
-
- /* we want background collision checking to occur only when the
- * spacecraft is near the bottom of the bitmap (i.e. it can crash
- * into the rocks on the ground but not the mountains in the
- * distance). we check the ANIM_COLLISION_BG bit in the flags
- * so that we enable or disable collision checking only once
- * each time we cross the threshold.
- */
- if (lem->anim->y > GROUND_THRESHOLD && !(lem->anim->flags & ANIM_COLLISION_BG)) {
- gs_enable_cplx_collision_bg(lem);
- } else if (lem->anim->y <= GROUND_THRESHOLD && (lem->anim->flags & ANIM_COLLISION_BG)) {
- gs_disable_cplx_collision_bg(lem);
- }
-
- /* show current stats */
- show_stats();
-
- /* show the next spacecraft animation frame as determined above */
- gs_anim_cplx(lem, lem->anim->x, lem->anim->y);
-
- /* rock star is dancing */
- dance();
-
- /* update the off-screen bitmap, then display it */
- mydelay(1);
- flipper();
-
- /* if we landed on the fuel platform, fill 'er up */
- /* this happens if collide with background color white or yellow */
- /* make sure landed slowly and more-or-less upright */
- if (craft.collision == 5 || craft.collision == 6) {
-
- if (craft.prev_vel <= SAFE_SPEED &&
- (craft.index == 0 || craft.index == 1 || craft.index == LC_ANIM_COUNT-1)) {
- /* landed on platform ok */
- if (craft.fuel < MAX_FUEL) {
- gs_stop_sound(THRUST_CHANNEL);
- thrusting = 0;
- refuel();
- }
- } else {
- /* crashed on platform */
- crash();
- break;
- }
- } else if (craft.collision) {
- /* collided with a rock */
- crash();
- break;
- } else if (craft.altitude == 0) {
- /* on the ground, let's see how we landed */
- gs_stop_sound(THRUST_CHANNEL);
- gs_stop_sound(WHOOP_CHANNEL);
-
- /* don't let rock star appear nearby if he's not visible yet */
- if (!rockstar_visible) {
- gs_stop_sound(PING_CHANNEL);
- allow_rockstar = 0;
- }
-
- craft.vel = 0;
- mydelay(2);
-
- if (craft.prev_vel <= SAFE_SPEED &&
- (craft.index == 0 || craft.index == 1 || craft.index == LC_ANIM_COUNT-1)) {
- /* a gentle upright landing! */
- thrusting = 0;
- if (safe_landing()) {
- /* won the game, start over */
- break;
- }
- /* otherwise continue the search */
- allow_rockstar = 1;
-
- /* if we sat on the ground waiting for him to appear,
- don't let him appear right away */
- if (!rockstar_visible) {
- rockstar_time = vbcounter + (gs_random(5) + 20) * TICKS_PER_SEC;
- }
- } else {
- /* too fast or tilted or hit a rock */
- crash();
- break;
- }
- }
- }
- }
- }
-
-