1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00
wine/test/hyperoid/hyperoid.c
Alexandre Julliard f0b2354c71 Release 0.4.3
Tue Sep 28 19:59:21 1993  David Metcalfe

	* [windows/win.c]
	Implemented support for windows with no borders.  Added
 	GetParent(), GetDlgCtrlID(), GetWindowText() and
	GetWindowTextLength() functions.

	* [misc/xt.c]
	Added processing of WM_GETTEXT and WM_GETTEXTLENGTH messages
	to DefWindowProc and Implemented MessageBeep().

	* [windows/syscolor.c]
	Added preliminary system color support.

	* [controls/button1.c]
	Mods to new button control and integration with Wine.

Tue Sep 28 19:59:21 1993  Johannes Ruscheinski

	* [controls/button1.c]
	New button control using GDI functions.
	
Tue Sep 28 19:59:21 1993  Eric Youngdale

	* [debugger/*]
	Added debugging capabilities to Wine

Sat Sep 25 13:22:50 1993  Alexandre Julliard  (julliard@di.epfl.ch)

	* [objects/region.c]
	Bug fix

Fri Sep 24 07:35:11 1993  Bob Amstadt  (bob at pooh)

	* [tools/build.c]
	Changed the entry point code to reduce the standard entry
	point size from 22 bytes to 10 bytes.  This leaves about
	4000 free entry points instead of the 800 in version 0.4.2.

	* [loader/resource.c]
	Rewrote functions to allow loading of resources from any
	DLL.

	* [loader/wine.c] [include/wine.h]
	Added functions GetFilenameFromInstance() and GetFileInfo()
	to search for a loaded file based on its instance handle.
	Added a field in struct w_files to make searching by an instance
	handle faster.

Tue Sep 21 09:57:01 1993  miguel@roxanne.nuclecu.unam.mx (Miguel de Icaza)

	* [misc/profile.c]
	Implementation of .INI file handling

Mon Sep 20 10:54:32 1993  David Metcalfe

	* [misc/profile.c.old]
	Implementation of .INI file handling

Mon Sep 20 10:54:32 1993  John Brezak

	* [controls/WinButton.c]
	Bug fix with call to XtVaSetValues.

Mon Sep 20 10:54:32 1993  Alexandre Julliard

	* [windows/win.c]
	Quick patch to get colormaps to work with button widget.

Mon Sep 20 02:42:54 1993    (yngvi@hafro.is)

	* misc/keyboard.c: 
	Ifdefed out some bogus Ansi<->Oem conversion functions

	* misc/lstr.c: 
	New file with string functions like lstr* IsChar* *Ansi* 

Wed Sep 15 20:35:10 1993  John Brezak

	* [loader/signal.c]
	Additional changes to support NetBSD.

Wed Sep 15 22:19:22 1993  Martin Ayotte

	* [windows/graphics.c]
	Added FrameRect function

Tue Sep 14 13:54:45 1993  Alexandre Julliard

	* [objects/color.c] [objects/palette.c]
	Preliminary support for private color map.

	* [windows/class.c]
	Implemented CS_CLASSDC style.

	* [windows/dce.c]
	Moved DCEs to USER heap.
	Implemented class and window DCs.

	* [windows/event.c]
	Implemented CS_DBLCLKS style.

	* [windows/graphics.c]
	Bug fix in SetPixel().

	* [windows/win.c]	
	Implemented CS_OWNDC style.
	Implemented Get/SetWindowLong().

	* [controls/menu.c] [windows/class.c] [windows/clipping.c] 
	  [windows/dce.c] [windows/message.c] [windows/win.c]	
	Moved windows from global heap to USER heap.
1993-09-29 12:21:49 +00:00

1851 lines
44 KiB
C

//
// HYPEROID - a neato game
//
// Version: 1.1 Copyright (C) 1990,91 Hutchins Software
// This software is licenced under the GNU General Public Licence
// Please read the associated legal documentation
// Author: Edward Hutchins
// Internet: eah1@cec1.wustl.edu
// USNail: c/o Edward Hutchins, 63 Ridgemoor Dr., Clayton, MO, 63105
// Revisions:
// 10/31/91 made game better/harder - Ed.
//
// Music: R.E.M./The Cure/Ministry/Front 242/The Smiths/New Order/Hendrix...
// Beers: Bass Ale, Augsberger Dark
//
#include "hyperoid.h"
//
// imports
//
IMPORT POINT LetterPart[] FROM( roidsupp.c );
IMPORT NPSTR szNumberDesc[] FROM( roidsupp.c );
IMPORT NPSTR szLetterDesc[] FROM( roidsupp.c );
//
// globals
//
GLOBAL CHAR szAppName[32];
GLOBAL HANDLE hAppInst;
GLOBAL HWND hAppWnd;
GLOBAL HPALETTE hAppPalette;
GLOBAL INT nDrawDelay;
GLOBAL INT nLevel;
GLOBAL INT nSafe;
GLOBAL INT nShield;
GLOBAL INT nBomb;
GLOBAL INT nBadGuys;
GLOBAL LONG lScore;
GLOBAL LONG lLastLife;
GLOBAL LONG lHighScore;
GLOBAL BOOL bRestart;
GLOBAL BOOL bPaused;
GLOBAL BOOL bBW;
GLOBAL INT vkShld;
GLOBAL INT vkClkw;
GLOBAL INT vkCtrClkw;
GLOBAL INT vkThrst;
GLOBAL INT vkRvThrst;
GLOBAL INT vkFire;
GLOBAL INT vkBomb;
GLOBAL NPOBJ npPlayer;
GLOBAL LIST FreeList;
GLOBAL LIST RoidList;
GLOBAL LIST ShotList;
GLOBAL LIST FlameList;
GLOBAL LIST SpinnerList;
GLOBAL LIST HunterList;
GLOBAL LIST HunterShotList;
GLOBAL LIST SwarmerList;
GLOBAL LIST LetterList;
GLOBAL LIST BonusList;
GLOBAL INT nCos[DEGREE_SIZE];
GLOBAL INT nSin[DEGREE_SIZE];
GLOBAL HPEN hPen[PALETTE_SIZE];
GLOBAL OBJ Obj[MAX_OBJS];
GLOBAL HBITMAP hBitmap[IDB_MAX];
//
// locals
//
LOCAL DWORD dwSeed;
LOCAL INT nScoreLen;
LOCAL CHAR szScore[40];
LOCAL RECT rectScoreClip;
LOCAL RECT rectShotClip;
LOCAL POINT Player[] =
{ {0, 0}, {160, 150}, {0, 250}, {96, 150}, {0, 0} };
LOCAL POINT Spinner[] =
{ {160, 150}, {224, 100}, {96, 100}, {32, 150}, {160, 150} };
LOCAL POINT Swarmer[] =
{ {0, 100}, {64, 100}, {128, 100}, {192, 100}, {0, 100} };
LOCAL POINT Hunter[] =
{
{160, 150}, {0, 250}, {192, 30}, {64, 30},
{0, 250}, {96, 150}, {128, 150}, {160, 150}
};
LOCAL POINT Bonus[] =
{ {0, 150}, {102, 150}, {205, 150}, {51, 150}, {154, 150}, {0, 150} };
//
// KillBadGuy - kill off a badguy (made into a macro)
//
#define KillBadGuy() \
((--nBadGuys <= 0)?(SetRestart( RESTART_NEXTLEVEL ),TRUE):FALSE)
//
// arand - pseudorandom number from 0 to x-1 (thanks antman!)
//
INT NEAR PASCAL arand( INT x )
{
dwSeed = dwSeed * 0x343fd + 0x269ec3;
return( (INT)(((dwSeed >> 16) & 0x7fff) * x >> 15) );
}
//
// AddHead - add an object to the head of a list
//
VOID NEAR PASCAL AddHead( NPLIST npList, NPNODE npNode )
{
if (npList->npHead)
{
npNode->npNext = npList->npHead;
npNode->npPrev = NULL;
npList->npHead = (npList->npHead->npPrev = npNode);
}
else // add to an empty list
{
npList->npHead = npList->npTail = npNode;
npNode->npNext = npNode->npPrev = NULL;
}
}
//
// RemHead - remove the first element in a list
//
NPNODE NEAR PASCAL RemHead( NPLIST npList )
{
if (npList->npHead)
{
NPNODE npNode = npList->npHead;
if (npList->npTail != npNode)
{
npList->npHead = npNode->npNext;
npNode->npNext->npPrev = NULL;
}
else npList->npHead = npList->npTail = NULL;
return( npNode );
}
else return( NULL );
}
//
// Remove - remove an arbitrary element from a list
//
VOID NEAR PASCAL Remove( NPLIST npList, NPNODE npNode )
{
if (npNode->npPrev) npNode->npPrev->npNext = npNode->npNext;
else npList->npHead = npNode->npNext;
if (npNode->npNext) npNode->npNext->npPrev = npNode->npPrev;
else npList->npTail = npNode->npPrev;
}
//
// DrawObject - draw a single object
//
VOID NEAR PASCAL DrawObject( HDC hDC, NPOBJ npObj )
{
INT nCnt;
INT nDir = (npObj->nDir += npObj->nSpin);
INT x = (npObj->Pos.x += npObj->Vel.x);
INT y = (npObj->Pos.y += npObj->Vel.y);
POINT Pts[MAX_PTS];
if (x < -CLIP_COORD) npObj->Pos.x = x = CLIP_COORD;
else if (x > CLIP_COORD) npObj->Pos.x = x = -CLIP_COORD;
if (y < -CLIP_COORD) npObj->Pos.y = y = CLIP_COORD;
else if (y > CLIP_COORD) npObj->Pos.y = y = -CLIP_COORD;
for (nCnt = npObj->byPts - 1; nCnt >= 0; --nCnt)
{
WORD wDeg = DEG( npObj->Pts[nCnt].x + nDir );
INT nLen = npObj->Pts[nCnt].y;
Pts[nCnt].x = x + MULDEG( nLen, nCos[wDeg] );
Pts[nCnt].y = y + MULDEG( nLen, nSin[wDeg] );
}
if (npObj->byPts > 1)
{
SelectObject( hDC, hPen[BLACK] );
Polyline( hDC, npObj->Old, npObj->byPts );
if (npObj->nCount > 0)
{
SelectObject( hDC, hPen[npObj->byColor] );
Polyline( hDC, Pts, npObj->byPts );
for (nCnt = npObj->byPts - 1; nCnt >= 0; --nCnt)
npObj->Old[nCnt] = Pts[nCnt];
}
}
else // just a point
{
SetPixel( hDC, npObj->Old[0].x, npObj->Old[0].y, PALETTEINDEX( BLACK ) );
if (npObj->nCount > 0)
{
SetPixel( hDC, Pts[0].x, Pts[0].y, PALETTEINDEX( npObj->byColor ) );
npObj->Old[0] = Pts[0];
}
}
}
//
// SetRestart - set the restart timer
//
VOID NEAR PASCAL SetRestart( RESTART_MODE Restart )
{
POINT Pt;
CHAR szBuff[32];
if (bRestart) return;
SetTimer( hAppWnd, RESTART_TIMER, RESTART_DELAY, NULL );
bRestart = TRUE;
Pt.x = Pt.y = 0;
switch (Restart)
{
case RESTART_GAME:
SpinLetters( "GAME OVER", Pt, Pt, RED, 400 );
break;
case RESTART_LEVEL:
PrintLetters( "GET READY", Pt, Pt, BLUE, 300 );
break;
case RESTART_NEXTLEVEL:
wsprintf( szBuff, "LEVEL %u", nLevel + 1 );
PrintLetters( szBuff, Pt, Pt, BLUE, 300 );
break;
}
}
//
// PrintPlayerMessage - show the player a status message
//
VOID NEAR PASCAL PrintPlayerMessage( NPSTR npszText )
{
POINT Pos, Vel;
Pos = npPlayer->Pos;
Pos.y -= 400;
Vel.x = 0;
Vel.y = -50;
PrintLetters( npszText, Pos, Vel, GREEN, 150 );
}
//
// AddExtraLife - give the player another life
//
VOID NEAR PASCAL AddExtraLife( VOID )
{
PrintPlayerMessage( "EXTRA LIFE" );
++npPlayer->nCount;
npPlayer->byColor = (BYTE)(BLACK + npPlayer->nCount);
if (npPlayer->byColor > WHITE) npPlayer->byColor = WHITE;
}
//
// Hit - something hit an object, do fireworks
//
VOID NEAR PASCAL Hit( HDC hDC, NPOBJ npObj )
{
INT nCnt;
for (nCnt = 0; nCnt < 6; ++nCnt)
{
NPOBJ npFlame = RemHeadObj( &FreeList );
if (!npFlame) return;
npFlame->Pos.x = npObj->Pos.x;
npFlame->Pos.y = npObj->Pos.y;
npFlame->Vel.x = npObj->Vel.x;
npFlame->Vel.y = npObj->Vel.y;
npFlame->nDir = npObj->nDir + (nCnt * DEGREE_SIZE) / 6;
npFlame->nSpin = 0;
npFlame->nCount = 10 + arand( 8 );
npFlame->byColor = YELLOW;
npFlame->byPts = 1;
npFlame->Pts[0].x = npFlame->Pts[0].y = 0;
ACCEL( npFlame, npFlame->nDir, 50 - npFlame->nCount );
AddHeadObj( &FlameList, npFlame );
}
}
//
// Explode - explode an object
//
VOID NEAR PASCAL Explode( HDC hDC, NPOBJ npObj )
{
INT nCnt, nSize = npObj->byPts;
DrawObject( hDC, npObj );
for (nCnt = 0; nCnt < nSize; ++nCnt)
{
NPOBJ npFlame;
if (arand( 2 )) continue;
if (!(npFlame = RemHeadObj( &FreeList ))) return;
npFlame->Pos.x = npObj->Pos.x;
npFlame->Pos.y = npObj->Pos.y;
npFlame->Vel.x = npObj->Vel.x;
npFlame->Vel.y = npObj->Vel.y;
npFlame->nDir = npObj->nDir + nCnt * DEGREE_SIZE / nSize + arand( 32 );
npFlame->nSpin = arand( 31 ) - 15;
npFlame->nCount = 25 + arand( 16 );
npFlame->byColor = npObj->byColor;
npFlame->byPts = 2;
npFlame->Pts[0] = npObj->Pts[nCnt];
if (nCnt == nSize - 1) npFlame->Pts[1] = npObj->Pts[0];
else npFlame->Pts[1] = npObj->Pts[nCnt + 1];
ACCEL( npFlame, npFlame->nDir, 60 - npFlame->nCount );
AddHeadObj( &FlameList, npFlame );
}
Hit( hDC, npObj );
}
//
// HitPlayer - blow up the player
//
BOOL NEAR PASCAL HitPlayer( HDC hDC, NPOBJ npObj )
{
POINT Vel;
INT nMass, nSpin;
if (nSafe || (npPlayer->nCount <= 0)) return( FALSE );
// rumble and shake both objects
nMass = npPlayer->nMass + npObj->nMass;
nSpin = npPlayer->nSpin + npObj->nSpin;
npObj->nSpin -= MulDiv( nSpin, npPlayer->nMass, nMass );
npPlayer->nSpin -= MulDiv( nSpin, npObj->nMass, nMass );
Vel.x = npPlayer->Vel.x - npObj->Vel.x;
Vel.y = npPlayer->Vel.y - npObj->Vel.y;
npObj->Vel.x += MulDiv( Vel.x, npPlayer->nMass, nMass );
npObj->Vel.y += MulDiv( Vel.y, npPlayer->nMass, nMass );
npPlayer->Vel.x -= MulDiv( Vel.x, npObj->nMass, nMass );
npPlayer->Vel.y -= MulDiv( Vel.y, npObj->nMass, nMass );
if (--npPlayer->nCount)
{
npPlayer->byColor = (BYTE)(BLACK + npPlayer->nCount);
if (npPlayer->byColor > WHITE) npPlayer->byColor = WHITE;
Hit( hDC, npPlayer );
return( TRUE );
}
// final death
npPlayer->byColor = WHITE;
Explode( hDC, npPlayer );
SetRestart( RESTART_GAME );
return( FALSE );
}
//
// CreateLetter - make a new letter object
//
NPOBJ FAR PASCAL CreateLetter( CHAR cLetter, INT nSize )
{
NPOBJ npLtr;
INT nCnt;
NPSTR npDesc;
if (cLetter >= '0' && cLetter <= '9') npDesc = szNumberDesc[cLetter - '0'];
else if (cLetter >= 'A' && cLetter <= 'Z') npDesc = szLetterDesc[cLetter - 'A'];
else if (cLetter >= 'a' && cLetter <= 'z') npDesc = szLetterDesc[cLetter - 'a'];
else if (cLetter == '.') npDesc = "l";
else return( NULL );
if (npLtr = RemHeadObj( &FreeList ))
{
npLtr->nMass = 1;
npLtr->nDir = 0;
npLtr->nSpin = 0;
npLtr->nCount = 40;
npLtr->byColor = WHITE;
npLtr->byPts = (BYTE)(nCnt = strlen( npDesc ));
while (nCnt--)
{
npLtr->Pts[nCnt] = LetterPart[npDesc[nCnt] - 'a'];
npLtr->Pts[nCnt].y = MulDiv( npLtr->Pts[nCnt].y, nSize, LETTER_MAX );
}
AddHeadObj( &LetterList, npLtr );
}
return( npLtr );
}
//
// DrawLetters - draw letters and such
//
VOID NEAR PASCAL DrawLetters( HDC hDC )
{
NPOBJ npLtr, npNext;
for (npLtr = HeadObj( &LetterList ); npLtr; npLtr = npNext)
{
npNext = NextObj( npLtr );
switch (--npLtr->nCount)
{
case 3:
--npLtr->byColor;
break;
case 0:
RemoveObj( &LetterList, npLtr );
AddHeadObj( &FreeList, npLtr );
break;
}
DrawObject( hDC, npLtr );
}
}
//
// CreateBonus - make a new bonus object
//
VOID NEAR PASCAL CreateBonus( VOID )
{
NPOBJ npBonus;
INT nCnt;
if (npBonus = RemHeadObj( &FreeList ))
{
npBonus->Pos.x = arand( CLIP_COORD * 2 ) - CLIP_COORD;
npBonus->Pos.y = -CLIP_COORD;
npBonus->Vel.x = npBonus->Vel.y = 0;
npBonus->nDir = arand( DEGREE_SIZE );
npBonus->nSpin = (arand( 2 ) ? 12 : -12);
npBonus->nCount = arand( 4 ) + 1;
npBonus->nDelay = 64 + arand( 128 );
npBonus->nMass = 1;
npBonus->byColor = (BYTE)(WHITE + (npBonus->nCount * 2));
npBonus->byPts = DIM(Bonus);
for (nCnt = 0; nCnt < DIM(Bonus); ++nCnt)
npBonus->Pts[nCnt] = Bonus[nCnt];
ACCEL( npBonus, npBonus->nDir, 30 + nLevel * 2 );
AddHeadObj( &BonusList, npBonus );
}
}
//
// DrawBonuses - process and draw the bonus list
//
VOID NEAR PASCAL DrawBonuses( HDC hDC )
{
NPOBJ npBonus, npNext;
LOCAL INT nNextBonus = 1000;
if (nBadGuys && (--nNextBonus < 0))
{
CreateBonus();
nNextBonus = 1000;
}
for (npBonus = HeadObj( &BonusList ); npBonus; npBonus = npNext)
{
NPOBJ npShot;
INT nDelta;
RECT rect;
npNext = NextObj( npBonus );
MKRECT( &rect, npBonus->Pos, 150 );
if (PTINRECT( &rect, npPlayer->Pos ))
{
if (npPlayer->nCount > 0) switch (npBonus->nCount)
{
case 1:
{
CHAR szBuff[32];
LONG lBonus = 1000L * nLevel;
if (lBonus == 0) lBonus = 500;
lScore += lBonus;
wsprintf( szBuff, "%ld", lBonus );
PrintPlayerMessage( szBuff );
}
break;
case 2:
nSafe = 15;
++nShield;
npPlayer->byColor = GREEN;
PrintPlayerMessage( "EXTRA SHIELD" );
break;
case 3:
++nBomb;
PrintPlayerMessage( "EXTRA BOMB" );
break;
case 4:
AddExtraLife();
break;
}
npBonus->nCount = 0;
Explode( hDC, npBonus );
RemoveObj( &BonusList, npBonus );
AddHeadObj( &FreeList, npBonus );
}
else if (INTRECT(&rect, &rectShotClip))
{
for (npShot = HeadObj( &ShotList ); npShot; npShot = NextObj( npShot ))
{
if (!PTINRECT( &rect, npShot->Pos )) continue;
npShot->nCount = 1;
npBonus->nCount = 0;
Explode( hDC, npBonus );
RemoveObj( &BonusList, npBonus );
AddHeadObj( &FreeList, npBonus );
}
}
if (npBonus->nCount && --npBonus->nDelay <= 0)
{
--npBonus->nCount;
npBonus->nDelay = 64 + arand( 128 );
npBonus->byColor = (BYTE)(WHITE + (npBonus->nCount * 2));
if (npBonus->nCount == 0)
{
Explode( hDC, npBonus );
RemoveObj( &BonusList, npBonus );
AddHeadObj( &FreeList, npBonus );
}
}
nDelta = npPlayer->Pos.x - npBonus->Pos.x;
while (nDelta < -16 || nDelta > 16) nDelta /= 2;
npBonus->Vel.x += nDelta - npBonus->Vel.x / 16;
nDelta = npPlayer->Pos.y - npBonus->Pos.y;
while (nDelta < -16 || nDelta > 16) nDelta /= 2;
npBonus->Vel.y += nDelta - npBonus->Vel.y / 16;
DrawObject( hDC, npBonus );
}
}
//
// DrawHunterShots - process and draw the hunter shot list
//
VOID NEAR PASCAL DrawHunterShots( HDC hDC )
{
NPOBJ npShot, npNext;
for (npShot = HeadObj( &HunterShotList ); npShot; npShot = npNext)
{
RECT rect;
npNext = NextObj( npShot );
MKRECT( &rect, npShot->Pos, 200 );
if (PTINRECT( &rect, npPlayer->Pos ))
{
HitPlayer( hDC, npShot );
npShot->nCount = 1;
}
switch (--npShot->nCount)
{
case 7:
npShot->byColor = DKGREEN;
break;
case 0:
RemoveObj( &HunterShotList, npShot );
AddHeadObj( &FreeList, npShot );
break;
}
DrawObject( hDC, npShot );
}
}
//
// FireHunterShot - fire a hunter bullet
//
VOID NEAR PASCAL FireHunterShot( NPOBJ npHunt )
{
NPOBJ npShot;
if (npShot = RemHeadObj( &FreeList ))
{
npShot->Pos.x = npHunt->Pos.x;
npShot->Pos.y = npHunt->Pos.y;
npShot->Vel.x = npHunt->Vel.x;
npShot->Vel.y = npHunt->Vel.y;
npShot->nMass = 8;
npShot->nDir = npHunt->nDir + arand( 5 ) - 2;
npShot->nSpin = (arand( 2 ) ? 10 : -10);
npShot->nCount = 16 + arand( 8 );
npShot->byColor = GREEN;
npShot->byPts = 2;
npShot->Pts[0].x = 128;
npShot->Pts[0].y = 50;
npShot->Pts[1].x = 0;
npShot->Pts[1].y = 50;
ACCEL( npShot, npShot->nDir, 200 + npShot->nCount );
AddHeadObj( &HunterShotList, npShot );
}
}
//
// CreateHunter - make a new hunter
//
VOID NEAR PASCAL CreateHunter( VOID )
{
NPOBJ npHunt;
INT nCnt;
if (npHunt = RemHeadObj( &FreeList ))
{
npHunt->Pos.x = arand( CLIP_COORD * 2 ) - CLIP_COORD;
npHunt->Pos.y = -CLIP_COORD;
npHunt->Vel.x = npHunt->Vel.y = 0;
npHunt->nMass = 256;
npHunt->nDir = arand( DEGREE_SIZE );
npHunt->nSpin = 0;
npHunt->nCount = 1 + arand( nLevel );
npHunt->nDelay = 2 + arand( 10 );
npHunt->byColor = CYAN;
npHunt->byPts = DIM(Hunter);
for (nCnt = 0; nCnt < DIM(Hunter); ++nCnt)
npHunt->Pts[nCnt] = Hunter[nCnt];
ACCEL( npHunt, npHunt->nDir, 30 + nLevel * 2 );
AddHeadObj( &HunterList, npHunt );
++nBadGuys;
}
}
//
// DrawHunters - process and draw the hunter list
//
VOID NEAR PASCAL DrawHunters( HDC hDC )
{
NPOBJ npHunt, npNext;
LOCAL INT nNextHunter = 200;
if (nBadGuys && (--nNextHunter < 0))
{
CreateHunter();
nNextHunter = 1000 + arand( 1000 ) - nLevel * 8;
}
for (npHunt = HeadObj( &HunterList ); npHunt; npHunt = npNext)
{
NPOBJ npShot;
RECT rect;
npNext = NextObj( npHunt );
MKRECT( &rect, npHunt->Pos, 200 );
if (PTINRECT( &rect, npPlayer->Pos ))
{
HitPlayer( hDC, npHunt );
--npHunt->nCount;
if (npHunt->nCount < 1)
{
KillBadGuy();
npHunt->byColor = CYAN;
Explode( hDC, npHunt );
RemoveObj( &HunterList, npHunt );
AddHeadObj( &FreeList, npHunt );
}
else if (npHunt->nCount == 1) npHunt->byColor = DKCYAN;
}
else if (INTRECT(&rect, &rectShotClip))
{
for (npShot = HeadObj( &ShotList ); npShot; npShot = NextObj( npShot ))
{
if (!PTINRECT( &rect, npShot->Pos )) continue;
npShot->nCount = 1;
lScore += npHunt->nCount * 1000;
if (--npHunt->nCount < 1)
{
KillBadGuy();
npHunt->byColor = CYAN;
Explode( hDC, npHunt );
RemoveObj( &HunterList, npHunt );
AddHeadObj( &FreeList, npHunt );
}
else
{
if (npHunt->nCount == 1) npHunt->byColor = DKCYAN;
Hit( hDC, npHunt );
}
break;
}
}
ACCEL( npHunt, npHunt->nDir, 8 );
npHunt->Vel.x -= npHunt->Vel.x / 16;
npHunt->Vel.y -= npHunt->Vel.y / 16;
if (--npHunt->nDelay <= 0)
{
npHunt->nDelay = arand( 10 );
npHunt->nSpin = arand( 11 ) - 5;
FireHunterShot( npHunt );
}
DrawObject( hDC, npHunt );
}
}
//
// CreateSwarmer - make a new swarmer
//
VOID NEAR PASCAL CreateSwarmer( POINT Pos, INT nDir, INT nCount )
{
NPOBJ npSwarm;
INT nCnt;
if (npSwarm = RemHeadObj( &FreeList ))
{
npSwarm->Pos = Pos;
npSwarm->Vel.x = npSwarm->Vel.y = 0;
npSwarm->nDir = nDir;
npSwarm->nSpin = arand( 31 ) - 15;
npSwarm->nCount = nCount;
npSwarm->nDelay = 64 + arand( 64 );
npSwarm->nMass = 32;
npSwarm->byColor = DKGREEN;
npSwarm->byPts = DIM(Swarmer);
for (nCnt = 0; nCnt < DIM(Swarmer); ++nCnt)
{
npSwarm->Pts[nCnt] = Swarmer[nCnt];
npSwarm->Pts[nCnt].y += nCount * 10;
}
ACCEL( npSwarm, npSwarm->nDir, 30 + nLevel * 2 );
AddHeadObj( &SwarmerList, npSwarm );
++nBadGuys;
}
}
//
// DrawSwarmers - process and draw the swarmer list
//
VOID NEAR PASCAL DrawSwarmers( HDC hDC )
{
NPOBJ npSwarm, npNext;
LOCAL INT nNextSwarmer = 1000;
if (nBadGuys && (--nNextSwarmer < 0))
{
POINT Pos;
Pos.x = arand( CLIP_COORD * 2 ) - CLIP_COORD;
Pos.y = -CLIP_COORD;
CreateSwarmer( Pos, arand( DEGREE_SIZE ), 8 + nLevel * 2 );
nNextSwarmer = 1000 + arand( 500 ) - nLevel * 4;
}
for (npSwarm = HeadObj( &SwarmerList ); npSwarm; npSwarm = npNext)
{
NPOBJ npShot;
RECT rect;
npNext = NextObj( npSwarm );
MKRECT( &rect, npSwarm->Pos, 150 + npSwarm->nCount * 10 );
if (PTINRECT( &rect, npPlayer->Pos ))
{
HitPlayer( hDC, npSwarm );
npSwarm->nCount = 0;
}
else if (INTRECT(&rect, &rectShotClip))
{
for (npShot = HeadObj( &ShotList ); npShot; npShot = NextObj( npShot ))
{
if (!PTINRECT( &rect, npShot->Pos )) continue;
npShot->nCount = 1;
lScore += npSwarm->nCount * 25;
npSwarm->nCount = 0;
break;
}
}
if (npSwarm->nCount <= 0)
{
npSwarm->byColor = GREEN;
KillBadGuy();
Explode( hDC, npSwarm );
RemoveObj( &SwarmerList, npSwarm );
AddHeadObj( &FreeList, npSwarm );
}
else
{
if ((npSwarm->nCount > 1) && (--npSwarm->nDelay <= 0))
{
INT nDir = arand( DEGREE_SIZE );
INT nCount = npSwarm->nCount / 2;
CreateSwarmer( npSwarm->Pos, nDir, nCount );
nCount = npSwarm->nCount - nCount;
CreateSwarmer( npSwarm->Pos, nDir + 128, nCount );
npSwarm->nCount = 0;
}
DrawObject( hDC, npSwarm );
}
}
}
//
// CreateSpinner - make a new spinner
//
VOID NEAR PASCAL CreateSpinner( VOID )
{
NPOBJ npSpin;
INT nCnt;
if (npSpin = RemHeadObj( &FreeList ))
{
npSpin->Pos.x = arand( CLIP_COORD * 2 ) - CLIP_COORD;
npSpin->Pos.y = -CLIP_COORD;
npSpin->Vel.x = npSpin->Vel.y = 0;
npSpin->nDir = arand( DEGREE_SIZE );
npSpin->nSpin = -12;
npSpin->nCount = 1 + arand( nLevel );
npSpin->nMass = 64 + npSpin->nCount * 32;
npSpin->byColor = (BYTE)(MAGENTA - npSpin->nCount);
npSpin->byPts = DIM(Spinner);
for (nCnt = 0; nCnt < DIM(Spinner); ++nCnt)
npSpin->Pts[nCnt] = Spinner[nCnt];
ACCEL( npSpin, npSpin->nDir, 30 + nLevel * 2 );
AddHeadObj( &SpinnerList, npSpin );
++nBadGuys;
}
}
//
// DrawSpinners - process and draw the spinner list
//
VOID NEAR PASCAL DrawSpinners( HDC hDC )
{
NPOBJ npSpin, npNext;
LOCAL INT nNextSpinner = 1000;
if (nBadGuys && (--nNextSpinner < 0))
{
CreateSpinner();
nNextSpinner = 100 + arand( 900 ) - nLevel * 2;
}
for (npSpin = HeadObj( &SpinnerList ); npSpin; npSpin = npNext)
{
NPOBJ npShot;
INT nDelta;
RECT rect;
npNext = NextObj( npSpin );
MKRECT( &rect, npSpin->Pos, 150 );
if (PTINRECT( &rect, npPlayer->Pos ))
{
HitPlayer( hDC, npSpin );
--npSpin->nCount;
npSpin->byColor = (BYTE)(MAGENTA - npSpin->nCount);
if (npSpin->nCount < 1)
{
KillBadGuy();
Explode( hDC, npSpin );
RemoveObj( &SpinnerList, npSpin );
AddHeadObj( &FreeList, npSpin );
}
}
else if (INTRECT(&rect, &rectShotClip))
{
for (npShot = HeadObj( &ShotList ); npShot; npShot = NextObj( npShot ))
{
if (!PTINRECT( &rect, npShot->Pos )) continue;
npShot->nCount = 1;
lScore += npSpin->nCount * 500;
npSpin->byColor = (BYTE)(MAGENTA - (--npSpin->nCount));
if (npSpin->nCount < 1)
{
KillBadGuy();
Explode( hDC, npSpin );
RemoveObj( &SpinnerList, npSpin );
AddHeadObj( &FreeList, npSpin );
}
else Hit( hDC, npSpin );
break;
}
}
nDelta = npPlayer->Pos.x - npSpin->Pos.x;
while (nDelta < -16 || nDelta > 16) nDelta /= 2;
npSpin->Vel.x += nDelta - npSpin->Vel.x / 16;
nDelta = npPlayer->Pos.y - npSpin->Pos.y;
while (nDelta < -16 || nDelta > 16) nDelta /= 2;
npSpin->Vel.y += nDelta - npSpin->Vel.y / 16;
DrawObject( hDC, npSpin );
}
}
//
// CreateRoid - make a new asteroid
//
VOID NEAR PASCAL CreateRoid( POINT Pos, POINT Vel, INT nSides, BYTE byColor,
INT nDir, INT nSpeed, INT nSpin )
{
NPOBJ npRoid;
INT nCnt;
if (npRoid = RemHeadObj( &FreeList ))
{
npRoid->Pos = Pos;
npRoid->Vel = Vel;
npRoid->nMass = nSides * 128;
npRoid->nDir = nDir;
npRoid->nSpin = nSpin + arand( 11 ) - 5;
npRoid->nCount = nSides * 100;
npRoid->byColor = byColor;
npRoid->byPts = (BYTE)(nSides + 1);
for (nCnt = 0; nCnt < nSides; ++nCnt)
{
npRoid->Pts[nCnt].x = nCnt * DEGREE_SIZE / nSides + arand( 30 );
npRoid->Pts[nCnt].y = (nSides - 1) * 100 + 20 + arand( 80 );
}
npRoid->Pts[nSides] = npRoid->Pts[0];
ACCEL( npRoid, nDir, nSpeed );
AddHeadObj( &RoidList, npRoid );
++nBadGuys;
}
}
//
// BreakRoid - break up an asteroid
//
VOID NEAR PASCAL BreakRoid( HDC hDC, NPOBJ npRoid, NPOBJ npShot )
{
INT nCnt, nNew;
lScore += npRoid->nCount;
if (npShot) npShot->nCount = 1;
switch (npRoid->byPts)
{
case 8:
nNew = 2 + arand( 3 );
break;
case 7:
nNew = 1 + arand( 3 );
break;
case 6:
nNew = 1 + arand( 2 );
break;
case 5:
nNew = arand( 2 );
break;
default:
nNew = 0;
break;
}
if (nNew == 1) // don't explode outward
{
POINT Pt = npRoid->Pos;
Pt.x += arand( 301 ) - 150; Pt.y += arand( 301 ) - 150;
CreateRoid( Pt, npRoid->Vel, npRoid->byPts - (nNew + 1),
npRoid->byColor, npShot->nDir, 8, npRoid->nSpin );
}
else if (nNew > 0)
{
INT nSpeed = npRoid->nSpin * npRoid->nSpin * nNew + 16;
for (nCnt = 0; nCnt < nNew; ++nCnt)
{
POINT Pt = npRoid->Pos;
Pt.x += arand( 601 ) - 300; Pt.y += arand( 601 ) - 300;
CreateRoid( Pt, npRoid->Vel, npRoid->byPts - (nNew + 1),
npRoid->byColor,
npRoid->nDir + nCnt * DEGREE_SIZE / nNew + arand( 32 ),
nSpeed + arand( nLevel * 4 ),
npRoid->nSpin / 2 );
}
}
KillBadGuy();
++npRoid->byColor;
npRoid->nCount = 0;
if (nNew)
{
Hit( hDC, npRoid );
DrawObject( hDC, npRoid );
}
else Explode( hDC, npRoid );
RemoveObj( &RoidList, npRoid );
AddHeadObj( &FreeList, npRoid );
}
//
// DrawRoids - process and draw the asteroid list
//
VOID NEAR PASCAL DrawRoids( HDC hDC )
{
NPOBJ npRoid, npNext;
for (npRoid = HeadObj( &RoidList ); npRoid; npRoid = npNext)
{
INT nSize = npRoid->nCount;
NPOBJ npShot;
RECT rect;
npNext = NextObj( npRoid );
DrawObject( hDC, npRoid );
MKRECT( &rect, npRoid->Pos, nSize );
if (PTINRECT( &rect, npPlayer->Pos ) && HitPlayer( hDC, npRoid ))
{
npPlayer->nCount = -npPlayer->nCount;
npPlayer->byColor = WHITE;
Explode( hDC, npPlayer );
BreakRoid( hDC, npRoid, NULL );
if (nBadGuys) SetRestart( RESTART_LEVEL );
else SetRestart( RESTART_NEXTLEVEL );
}
else if (INTRECT(&rect, &rectShotClip))
{
for (npShot = HeadObj( &ShotList ); npShot; npShot = NextObj( npShot ))
{
if (!PTINRECT( &rect, npShot->Pos )) continue;
BreakRoid( hDC, npRoid, npShot );
break;
}
}
}
}
//
// DrawShots - process and draw the player shot list
//
VOID NEAR PASCAL DrawShots( HDC hDC )
{
NPOBJ npShot, npNext;
if (npShot = HeadObj( &ShotList ))
{
rectShotClip.left = rectShotClip.right = npShot->Pos.x;
rectShotClip.top = rectShotClip.bottom = npShot->Pos.y;
while (npShot)
{
npNext = NextObj( npShot );
switch (--npShot->nCount)
{
case 10:
npShot->byColor = DKCYAN;
break;
case 5:
npShot->byColor = DKBLUE;
break;
case 0:
RemoveObj( &ShotList, npShot );
AddHeadObj( &FreeList, npShot );
break;
}
DrawObject( hDC, npShot );
if (npShot->Pos.x < rectShotClip.left) rectShotClip.left = npShot->Pos.x;
else if (npShot->Pos.x > rectShotClip.right) rectShotClip.right = npShot->Pos.x;
if (npShot->Pos.y < rectShotClip.top) rectShotClip.top = npShot->Pos.y;
else if (npShot->Pos.y > rectShotClip.bottom) rectShotClip.bottom = npShot->Pos.y;
npShot = npNext;
}
}
else rectShotClip.left = rectShotClip.right = rectShotClip.top = rectShotClip.bottom = 32767;
}
//
// DrawFlames - process and draw the flame list
//
VOID NEAR PASCAL DrawFlames( HDC hDC )
{
NPOBJ npFlame, npNext;
for (npFlame = HeadObj( &FlameList ); npFlame; npFlame = npNext)
{
npNext = NextObj( npFlame );
switch (--npFlame->nCount)
{
case 7:
npFlame->byColor = RED;
break;
case 3:
npFlame->byColor = DKRED;
break;
case 0:
RemoveObj( &FlameList, npFlame );
AddHeadObj( &FreeList, npFlame );
break;
}
DrawObject( hDC, npFlame );
}
}
//
// FireShot - fire a bullet
//
VOID NEAR PASCAL FireShot( VOID )
{
NPOBJ npShot;
if (npShot = RemHeadObj( &FreeList ))
{
npShot->Pos.x = npPlayer->Pos.x;
npShot->Pos.y = npPlayer->Pos.y;
npShot->Vel.x = npPlayer->Vel.x;
npShot->Vel.y = npPlayer->Vel.y;
npShot->nMass = 8;
npShot->nDir = npPlayer->nDir + arand( 5 ) - 2;
npShot->nSpin = 0;
npShot->nCount = 16 + arand( 8 );
npShot->byColor = CYAN;
npShot->byPts = 2;
npShot->Pts[0].x = 128;
npShot->Pts[0].y = 50;
npShot->Pts[1].x = 0;
npShot->Pts[1].y = 50;
ACCEL( npShot, npShot->nDir, 200 + npShot->nCount );
AddHeadObj( &ShotList, npShot );
}
}
//
// AccelPlayer - move the player forward
//
VOID NEAR PASCAL AccelPlayer( INT nDir, INT nAccel )
{
NPOBJ npFlame;
nDir += npPlayer->nDir;
if (nAccel) ACCEL( npPlayer, nDir, nAccel );
if (npFlame = RemHeadObj( &FreeList ))
{
npFlame->Pos.x = npPlayer->Pos.x;
npFlame->Pos.y = npPlayer->Pos.y;
npFlame->Vel.x = npPlayer->Vel.x;
npFlame->Vel.y = npPlayer->Vel.y;
npFlame->nDir = nDir + 100 + arand( 57 );
npFlame->nSpin = 0;
npFlame->nCount = nAccel + arand( 7 );
npFlame->byColor = YELLOW;
npFlame->byPts = 1;
npFlame->Pts[0].x = npFlame->Pts[0].y = 0;
ACCEL( npFlame, npFlame->nDir, 50 + arand( 10 ) );
AddHeadObj( &FlameList, npFlame );
}
}
//
// DrawPlayer - process and draw the player
//
VOID NEAR PASCAL DrawPlayer( HDC hDC )
{
LOCAL INT nBombing = 0;
LOCAL INT nShotDelay = 0;
if (npPlayer->nCount <= 0) return;
if (nSafe > 0)
{
if (--nSafe == 0)
{
npPlayer->byColor = (BYTE)(BLACK + npPlayer->nCount);
if (npPlayer->byColor > WHITE) npPlayer->byColor = WHITE;
}
}
else if (IsKeyDown( vkShld ) && nShield > 0)
{
nSafe = 15;
if (--nShield > 0) npPlayer->byColor = GREEN;
else npPlayer->byColor = DKGREEN;
}
if (nBombing > 0)
{
if (--nBombing == 0)
{
ExplodeBadguys( hDC, &SpinnerList );
ExplodeBadguys( hDC, &SwarmerList );
ExplodeBadguys( hDC, &HunterList );
}
else
{
HitList( hDC, &SpinnerList );
HitList( hDC, &SwarmerList );
HitList( hDC, &HunterList );
}
}
else if (nBomb && IsKeyDown( vkBomb )) --nBomb, nBombing = 5;
if (IsKeyDown( vkClkw )) npPlayer->nSpin += 8;
if (IsKeyDown( vkCtrClkw )) npPlayer->nSpin -= 8;
if (IsKeyDown( vkThrst )) AccelPlayer( 0, 12 );
if (IsKeyDown( vkRvThrst )) AccelPlayer( 128, 12 );
if (nShotDelay) --nShotDelay;
else if (IsKeyDown( vkFire )) FireShot(), nShotDelay = 2;
DrawObject( hDC, npPlayer );
npPlayer->nSpin /= 2;
}
//
// GetHyperoidDC - get the correct DC for hyperoid rendering
//
HDC NEAR PASCAL GetHyperoidDC( HWND hWnd )
{
HDC hDC;
INT cx, cy;
RECT rect;
GetClientRect( hWnd, &rect );
cx = rect.right - rect.left;
cy = rect.bottom - rect.top;
hDC = GetDC( hWnd );
// set up the mapping mode
SetMapMode( hDC, MM_ISOTROPIC );
SetWindowExt( hDC, MAX_COORD, MAX_COORD );
SetViewportExt( hDC, cx / 2, -cy / 2 );
SetViewportOrg( hDC, cx / 2, cy / 2 );
// realize the palette
SelectPalette( hDC, hAppPalette, 0 );
RealizePalette( hDC );
return( hDC );
}
//
// DrawObjects - transform and redraw everything in the system
//
VOID NEAR PASCAL DrawObjects( HWND hWnd )
{
HDC hDC = GetHyperoidDC( hWnd );
// move and draw things (I don't think the order is important...)
DrawPlayer( hDC );
DrawFlames( hDC );
DrawShots( hDC );
DrawRoids( hDC );
DrawSpinners( hDC );
DrawSwarmers( hDC );
DrawHunters( hDC );
DrawHunterShots( hDC );
DrawLetters( hDC );
DrawBonuses( hDC );
// (...but I'm not changing it!!! :-)
ReleaseDC( hWnd, hDC );
}
//
// SetIndicator - set a quantity indicator
//
INT NEAR PASCAL SetIndicator( NPSTR npBuff, CHAR IDBitmap, INT nQuant )
{
if (nQuant > 5)
{
*npBuff++ = IDBitmap; *npBuff++ = IDBitmap;
*npBuff++ = IDBitmap; *npBuff++ = IDBitmap;
*npBuff++ = IDB_plus;
}
else
{
INT nBlank = 5 - nQuant;
while (nQuant--) *npBuff++ = IDBitmap;
while (nBlank--) *npBuff++ = IDB_blank;
}
return( 5 );
}
//
// CheckScore - show the score and such stuff
//
VOID NEAR PASCAL CheckScore( HWND hWnd )
{
CHAR szBuff[sizeof(szScore)];
NPSTR npBuff = szBuff;
INT nLives, nLen, nCnt, x, y;
HBITMAP hbmOld;
HDC hDC, hDCMem;
if (IsIconic( hWnd )) return;
if (lScore - lLastLife > EXTRA_LIFE)
{
AddExtraLife();
lLastLife = lScore;
}
nLives = ((npPlayer->nCount > 0) ? npPlayer->nCount : -npPlayer->nCount);
*npBuff++ = IDB_level;
wsprintf( npBuff, "%2.2u", nLevel );
while (isdigit( *npBuff ))
*npBuff = (CHAR)(*npBuff + IDB_num0 - '0'), ++npBuff;
*npBuff++ = IDB_blank; *npBuff++ = IDB_score;
wsprintf( npBuff, "%7.7lu", lScore );
while (isdigit( *npBuff ))
*npBuff = (CHAR)(*npBuff + IDB_num0 - '0'), ++npBuff;
*npBuff++ = IDB_blank;
npBuff += SetIndicator( npBuff, IDB_life, nLives );
npBuff += SetIndicator( npBuff, IDB_shield, nShield );
npBuff += SetIndicator( npBuff, IDB_bomb, nBomb );
nLen = npBuff - szBuff;
hDC = GetWindowDC( hWnd );
IntersectClipRect( hDC, rectScoreClip.left, rectScoreClip.top,
rectScoreClip.right, rectScoreClip.bottom );
hDCMem = CreateCompatibleDC( hDC );
hbmOld = SelectObject( hDCMem, hBitmap[0] );
x = rectScoreClip.left;
y = rectScoreClip.top;
for (nCnt = 0; nCnt < nLen; ++nCnt)
{
if (szBuff[nCnt] != szScore[nCnt])
{
SelectObject( hDCMem, hBitmap[szBuff[nCnt] - IDB_blank] );
BitBlt( hDC, x, y, CX_BITMAP, CY_BITMAP, hDCMem, 0, 0, SRCCOPY );
szScore[nCnt] = szBuff[nCnt];
}
x += CX_BITMAP;
}
if (nCnt < nScoreLen)
{
SelectObject( hDCMem, hBitmap[0] );
do {
if (szScore[nCnt] != IDB_blank)
{
BitBlt( hDC, x, y, CX_BITMAP, CY_BITMAP, hDCMem, 0, 0, SRCCOPY );
szScore[nCnt] = IDB_blank;
}
x += CX_BITMAP;
} while (++nCnt < nScoreLen);
}
nScoreLen = nLen;
SelectObject( hDCMem, hbmOld );
DeleteDC( hDCMem );
ReleaseDC( hWnd, hDC );
}
//
// HitList - Hit() a list of things
//
VOID NEAR PASCAL HitList( HDC hDC, NPLIST npList )
{
NPOBJ npObj;
for (npObj = HeadObj( npList ); npObj; npObj = NextObj( npObj ))
if (npObj->nCount) Hit( hDC, npObj );
}
//
// ExplodeBadguys - explode a list of badguys
//
VOID NEAR PASCAL ExplodeBadguys( HDC hDC, NPLIST npList )
{
NPOBJ npObj;
while (npObj = HeadObj( npList ))
{
KillBadGuy();
npObj->nCount = 0;
Explode( hDC, npObj );
RemoveObj( npList, npObj );
AddHeadObj( &FreeList, npObj );
}
}
//
// NewGame - start a new game
//
VOID NEAR PASCAL NewGame( HWND hWnd )
{
HDC hDC = GetHyperoidDC( hWnd );
npPlayer->nCount = 0;
npPlayer->byColor = WHITE;
Explode( hDC, npPlayer );
SetRestart( RESTART_GAME );
ExplodeBadguys( hDC, &RoidList );
ExplodeBadguys( hDC, &SpinnerList );
ExplodeBadguys( hDC, &SwarmerList );
ExplodeBadguys( hDC, &HunterList );
ReleaseDC( hWnd, hDC );
}
//
// RestartHyperoid - set up a game!
//
VOID NEAR PASCAL RestartHyperoid( VOID )
{
if (npPlayer->nCount == 0)
{
POINT Pos, Vel;
Pos.x = 0;
Pos.y = -CLIP_COORD / 2;
Vel.x = 0;
Vel.y = 150;
PrintLetters( szAppName, Pos, Vel, YELLOW, 800 );
npPlayer->nCount = 3;
if (lHighScore < lScore) lHighScore = lScore;
lLastLife = lScore = 0;
nLevel = 0;
nShield = nBomb = 3;
}
else if (npPlayer->nCount < 0)
{
// cheesy way of restarting after a major collision
npPlayer->nCount = -npPlayer->nCount;
nShield = nBomb = 3;
}
npPlayer->Pos.x = npPlayer->Pos.y = 0;
npPlayer->Vel.x = npPlayer->Vel.y = 0;
npPlayer->nDir = 64;
npPlayer->nSpin = 0;
npPlayer->byColor = GREEN;
nSafe = 30;
if (ShotList.npHead)
{
NPOBJ npShot;
for (npShot = HeadObj( &ShotList ); npShot; npShot = NextObj( npShot ))
npShot->nCount = 1;
}
// reseed the asteroid field
if (nBadGuys == 0)
{
INT nCnt;
++nLevel;
for (nCnt = 5 + nLevel; nCnt; --nCnt)
{
POINT Pos, Vel;
Pos.x = arand( MAX_COORD * 2 ) - MAX_COORD;
Pos.y = arand( MAX_COORD * 2 ) - MAX_COORD;
Vel.x = Vel.y = 0;
CreateRoid( Pos, Vel, 6 + arand( 2 ),
(BYTE)(arand( 2 ) ? DKYELLOW : DKGREY),
arand( DEGREE_MAX ), 30 + arand( nLevel * 8 ), 0 );
}
}
}
//
// Panic - boss key (or just pause)
//
VOID NEAR PASCAL Panic( BOOL bPanic )
{
if (bPanic && !bPaused)
{
bPaused = TRUE;
KillTimer( hAppWnd, DRAW_TIMER );
SetWindowText( hAppWnd, "Program Manager Help - PROGMAN.HLP" );
ShowWindow( hAppWnd, SW_SHOWMINNOACTIVE );
InvalidateRect( hAppWnd, NULL, TRUE );
}
else if (bPaused) // double-panic == normal
{
bPaused = FALSE;
SetWindowText( hAppWnd, szAppName );
if (bPanic) ShowWindow( hAppWnd, SW_RESTORE );
SetTimer( hAppWnd, DRAW_TIMER, nDrawDelay, NULL );
}
}
//
// PaintHyperoid - paint the hyperoid window
//
VOID NEAR PASCAL PaintHyperoid( HWND hWnd )
{
PAINTSTRUCT ps;
BeginPaint( hWnd, &ps );
if (bPaused) DrawIcon( ps.hdc, 2, 2, LoadIcon( hAppInst, INTRES(IDI_PANIC) ) );
EndPaint( hWnd, &ps );
}
//
// EraseHyperoidBkgnd - fill in the background
//
BOOL NEAR PASCAL EraseHyperoidBkgnd( HWND hWnd, HDC hDC )
{
HBRUSH hbr;
RECT rect;
GetClientRect( hWnd, &rect );
if (bPaused)
{
SetBrushOrg( hDC, 0, 0 );
hbr = CreateSolidBrush( GetSysColor( COLOR_BACKGROUND ) );
}
else
{
SelectPalette( hDC, hAppPalette, 0 );
RealizePalette( hDC );
hbr = CreateSolidBrush( PALETTEINDEX( BLACK ) );
}
FillRect( hDC, &rect, hbr );
DeleteObject( hbr );
return( TRUE );
}
//
// DrawShadowRect - draw a shaded rectangle around an object
//
VOID NEAR PASCAL DrawShadowRect( HDC hDC, NPRECT npRect, HPEN hHi, HPEN hLo )
{
SelectObject( hDC, hHi );
MoveTo( hDC, npRect->right, npRect->top );
LineTo( hDC, npRect->left, npRect->top );
LineTo( hDC, npRect->left, npRect->bottom );
SelectObject( hDC, hLo );
LineTo( hDC, npRect->right, npRect->bottom );
LineTo( hDC, npRect->right, npRect->top );
}
//
// NCPaintHyperoid - paint a custom frame
//
VOID NEAR PASCAL NCPaintHyperoid( HWND hWnd )
{
HDC hDC, hDCMem;
INT cx, cy, cyCap, h;
HPEN hpenHi, hpenLo;
HBRUSH hbr;
HBITMAP hbm, hbmOld;
BITMAP bm;
RECT rect;
if (IsIconic( hWnd )) return;
hDC = GetWindowDC( hWnd );
GetWindowRect( hWnd, &rect );
rect.right -= rect.left, rect.left = 0;
rect.bottom -= rect.top, rect.top = 0;
cx = GetSystemMetrics( SM_CXFRAME );
cy = GetSystemMetrics( SM_CYFRAME );
cyCap = cy + GetSystemMetrics( SM_CYCAPTION ) - 1;
h = rect.bottom - (cyCap + cy);
SelectPalette( hDC, hAppPalette, 0 );
RealizePalette( hDC );
if (bBW)
{
hbr = SelectObject( hDC, CreateSolidBrush( PALETTEINDEX( WHITE ) ) );
hpenHi = hPen[BLACK];
hpenLo = hPen[BLACK];
}
else
{
hbr = SelectObject( hDC, CreateSolidBrush( PALETTEINDEX( GREY ) ) );
hpenHi = hPen[WHITE];
hpenLo = hPen[DKGREY];
}
PatBlt( hDC, 0, 0, rect.right, cyCap, PATCOPY );
PatBlt( hDC, 0, rect.bottom - cy, rect.right, rect.bottom, PATCOPY );
PatBlt( hDC, 0, cyCap, cx, h, PATCOPY );
PatBlt( hDC, rect.right - cx, cyCap, cx, h, PATCOPY );
--rect.bottom; --rect.right;
DrawShadowRect( hDC, &rect, hpenHi, hpenLo );
--cx; --cy;
rect.left += cx; rect.top += cy;
rect.right -= cx; rect.bottom -= cy;
if (!bBW) DrawShadowRect( hDC, &rect, hpenLo, hpenHi );
// get the title bar rect
++rect.left; ++rect.top; --rect.right;
rect.bottom = rect.top + cyCap - (cy + 2);
DrawShadowRect( hDC, &rect, hpenHi, hpenLo );
++rect.right; // for zoom/restore bitmap
hDCMem = CreateCompatibleDC( hDC );
hbm = LoadBitmap( NULL, INTRES(OBM_CLOSE) );
GetObject( hbm, sizeof(bm), (LPSTR)&bm );
bm.bmWidth /= 2; // they packed two images in here!
hbmOld = SelectObject( hDCMem, hbm );
BitBlt( hDC, rect.left, rect.top, bm.bmWidth, bm.bmHeight, hDCMem, 0, 0, SRCCOPY );
rect.left += bm.bmWidth;
if (IsZoomed( hWnd )) hbm = LoadBitmap( NULL, INTRES(OBM_RESTORE) );
else hbm = LoadBitmap( NULL, INTRES(OBM_ZOOM) );
GetObject( hbm, sizeof(bm), (LPSTR)&bm );
SelectObject( hDCMem, hbm );
rect.right -= bm.bmWidth;
BitBlt( hDC, rect.right, rect.top, bm.bmWidth, bm.bmHeight, hDCMem, 0, 0, SRCCOPY );
hbm = LoadBitmap( NULL, INTRES(OBM_REDUCE) );
GetObject( hbm, sizeof(bm), (LPSTR)&bm );
SelectObject( hDCMem, hbm );
rect.right -= bm.bmWidth;
BitBlt( hDC, rect.right, rect.top, bm.bmWidth, bm.bmHeight, hDCMem, 0, 0, SRCCOPY );
--rect.right;
DrawShadowRect( hDC, &rect, hpenHi, hpenLo );
// clip the score to the free titlebar area
++rect.left; ++rect.top;
rectScoreClip = rect;
DeleteObject( SelectObject( hDCMem, hbmOld ) );
DeleteObject( SelectObject( hDC, hbr ) );
DeleteDC( hDCMem );
ReleaseDC( hWnd, hDC );
// make sure the score gets redrawn
for (cx = 0; cx < nScoreLen; ++cx) szScore[cx] = '\0';
}
//
// HyperoidWndProc - the main window proc for Hyperoid
//
LONG FAR PASCAL EXPORT HyperoidWndProc( HWND hWnd, unsigned message,
WORD wParam, LONG lParam )
{
switch (message)
{
case WM_CREATE:
RestartHyperoid();
SetTimer( hWnd, DRAW_TIMER, nDrawDelay, NULL );
NCPaintHyperoid( hWnd );
break;
case WM_TIMER:
switch (wParam)
{
case DRAW_TIMER:
CheckScore( hWnd );
DrawObjects( hWnd );
return( 0 );
case RESTART_TIMER:
KillTimer( hWnd, RESTART_TIMER );
bRestart = FALSE;
RestartHyperoid();
return( 0 );
}
break;
case WM_SYSCOMMAND:
switch (wParam)
{
case IDM_NEW:
NewGame( hWnd );
break;
case IDM_ABOUT:
AboutHyperoid( hWnd );
break;
default:
return( DefWindowProc( hWnd, message, wParam, lParam ) );
}
break;
case WM_QUERYOPEN:
Panic( FALSE );
return( DefWindowProc( hWnd, message, wParam, lParam ) );
case WM_CHAR:
if (wParam == VK_ESCAPE) Panic( TRUE );
break;
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_SYSCHAR:
if (lParam & (1L<<29)) // alt key is down
{
return( DefWindowProc( hWnd, message, wParam, lParam ) );
}
switch (wParam)
{
case VK_ESCAPE:
if (message == WM_SYSKEYDOWN) Panic( TRUE );
return( 0 );
case VK_SPACE:
case VK_TAB:
return( 0 );
default:
return( DefWindowProc( hWnd, message, wParam, lParam ) );
}
break;
case WM_ERASEBKGND:
return( EraseHyperoidBkgnd( hWnd, (HDC)wParam ) );
case WM_NCACTIVATE:
case WM_NCPAINT:
NCPaintHyperoid( hWnd );
return( TRUE );
case WM_PAINT:
PaintHyperoid( hWnd );
break;
case WM_QUERYNEWPALETTE:
{
HDC hDC = GetDC( hWnd );
SelectPalette( hDC, hAppPalette, 0 );
RealizePalette( hDC );
ReleaseDC( hWnd, hDC );
}
return( TRUE );
case WM_DESTROY:
KillTimer( hWnd, DRAW_TIMER );
KillTimer( hWnd, RESTART_TIMER );
SaveHyperoidWindowPos( hWnd );
PostQuitMessage( 0 );
break;
default:
return( DefWindowProc( hWnd, message, wParam, lParam ) );
}
return( 0 );
}
//
// InitHyperoid - initialize everything
//
BOOL NEAR PASCAL InitHyperoid( VOID )
{
DOUBLE dRad;
INT nCnt;
// allocate the logical palette
hAppPalette = CreateHyperoidPalette();
if (!hAppPalette) return( FALSE );
for (nCnt = 0; nCnt < PALETTE_SIZE; ++nCnt)
{
hPen[nCnt] = CreatePen( PS_SOLID, 1, PALETTEINDEX( nCnt ) );
if (!hPen[nCnt]) return( FALSE );
}
for (nCnt = 0; nCnt < IDB_MAX; ++nCnt)
{
hBitmap[nCnt] = LoadBitmap( hAppInst, INTRES(IDB_blank + nCnt) );
if (!hPen[nCnt]) return( FALSE );
}
// seed the randomizer
dwSeed = GetCurrentTime();
// create the lookup table (should use resources)
for (nCnt = 0; nCnt < DEGREE_SIZE; ++nCnt)
{
dRad = nCnt * 6.2831855 / DEGREE_SIZE;
nCos[nCnt] = (INT)(DEGREE_MAX * cos( dRad ));
nSin[nCnt] = (INT)(DEGREE_MAX * sin( dRad ));
}
// get the initialization file info
GetHyperoidIni();
// allocate all objects as free
for (nCnt = 0; nCnt < MAX_OBJS; ++nCnt)
AddHeadObj( &FreeList, &(Obj[nCnt]) );
// set up the player
npPlayer = RemHeadObj( &FreeList );
npPlayer->byPts = DIM(Player);
npPlayer->nMass = 256;
for (nCnt = 0; nCnt < DIM(Player); ++nCnt)
npPlayer->Pts[nCnt] = Player[nCnt];
return( TRUE );
}
//
// ExitHyperoid - quit the damn game already!
//
VOID NEAR PASCAL ExitHyperoid( VOID )
{
INT nCnt;
if (hAppPalette) DeleteObject( hAppPalette );
for (nCnt = 0; nCnt < PALETTE_SIZE; ++nCnt)
if (hPen[nCnt]) DeleteObject( hPen[nCnt] );
for (nCnt = 0; nCnt < IDB_MAX; ++nCnt)
if (hBitmap[nCnt]) DeleteObject( hBitmap[nCnt] );
}
//
// WinMain - everybody has to have one
//
INT FAR PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, INT nCmdShow )
{
MSG msg;
hAppInst = hInstance;
if (!hPrevInstance)
{
// create the class if we're first
if (!CreateHyperoidClass()) return( FALSE );
}
else
{
// Copy data from previous instance
GetInstanceData( hPrevInstance, (PSTR)szAppName, sizeof(szAppName) );
}
if (!InitHyperoid()) goto Abort; // I LOVE GOTOS! REALLY I DO!
hAppWnd = CreateHyperoidWindow( lpszCmdLine, nCmdShow );
if (!hAppWnd) return( FALSE );
while (GetMessage( &msg, NULL, 0, 0 ))
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
Abort:
ExitHyperoid();
return( msg.wParam );
}