ref: b09f9d2dd1242bbe3298d6b2d5b2e7749c21dd32
parent: 6e467c170e62f4a5fe7c9ea677cecb540c043a0d
author: Iliyas Jorio <[email protected]>
date: Thu Feb 9 14:53:07 EST 2023
Most of the game is really just pure C
--- /dev/null
+++ b/src/MTypes.c
@@ -1,0 +1,37 @@
+///
+/// MTypes.c
+///
+/// Generic replacements for very basic Mac types.
+///
+/// John Stiles, 2002/10/14
+///
+
+
+#include "MTypes.h"
+
+
+void UnionMRect( const MRect* a, const MRect* b, MRect* u )
+{
+ u->top = MinShort( a->top, b->top );
+ u->left = MinShort( a->left, b->left );
+ u->bottom = MaxShort( a->bottom, b->bottom );
+ u->right = MaxShort( a->right, b->right );
+}
+
+
+void OffsetMRect( MRect* r, int x, int y )
+{
+ r->top += y;
+ r->left += x;
+ r->bottom += y;
+ r->right += x;
+}
+
+
+unsigned char MPointInMRect( MPoint p, const MRect* r )
+{
+ return (p.h >= r->left) &&
+ (p.h < r->right) &&
+ (p.v >= r->top) &&
+ (p.v < r->bottom);
+}
--- a/src/MTypes.cpp
+++ /dev/null
@@ -1,41 +1,0 @@
-///
-/// MTypes.c
-///
-/// Generic replacements for very basic Mac types.
-///
-/// John Stiles, 2002/10/14
-///
-
-
-#include "MTypes.h"
-#include <algorithm>
-
-using std::min;
-using std::max;
-
-
-void UnionMRect( const MRect* a, const MRect* b, MRect* u )
-{
- u->top = min( a->top, b->top );
- u->left = min( a->left, b->left );
- u->bottom = max( a->bottom, b->bottom );
- u->right = max( a->right, b->right );
-}
-
-
-void OffsetMRect( MRect* r, int x, int y )
-{
- r->top += y;
- r->left += x;
- r->bottom += y;
- r->right += x;
-}
-
-
-unsigned char MPointInMRect( MPoint p, const MRect* r )
-{
- return (p.h >= r->left) &&
- (p.h < r->right) &&
- (p.v >= r->top) &&
- (p.v < r->bottom);
-}
--- a/src/MTypes.h
+++ b/src/MTypes.h
@@ -8,7 +8,8 @@
#pragma once
-#include <cstdint>
+#include <stdint.h>
+#include <stdbool.h>
typedef signed char MBoolean;
@@ -15,28 +16,28 @@
typedef uint32_t MTicks;
-struct MRGBColor
+typedef struct MRGBColor
{
unsigned short red;
unsigned short green;
unsigned short blue;
-};
+} MRGBColor;
-struct MRect
+typedef struct MRect
{
short top;
short left;
short bottom;
- short right;
-};
+ short right;
+} MRect;
-struct MPoint
+typedef struct MPoint
{
short v;
short h;
-};
+} MPoint;
void UnionMRect( const MRect* a, const MRect* b, MRect* u );
@@ -43,3 +44,8 @@
void OffsetMRect( MRect* r, int x, int y );
unsigned char MPointInMRect( MPoint p, const MRect* r );
+
+static inline short MinShort(short a, short b) { return a < b ? a : b; }
+static inline short MaxShort(short a, short b) { return a < b ? b : a; }
+static inline int MinInt(int a, int b) { return a < b ? a : b; }
+static inline int MaxInt(int a, int b) { return a < b ? b : a; }
--- /dev/null
+++ b/src/SDLU.c
@@ -1,0 +1,580 @@
+///
+/// SDLU.c
+///
+/// SDL utilities.
+///
+/// John Stiles, 2002/10/12
+///
+
+#include "SDLU.h"
+#include "gameticks.h"
+#include "music.h"
+#include "main.h" // for Error
+
+// for acquiresurface
+#define k_acquireMax 10
+static int s_acquireHead = -1;
+static SDL_Surface* s_acquireList[k_acquireMax];
+
+// for initsurface
+static SDL_Palette* s_grayscalePalette;
+
+// for button and getmouse
+static int s_mouseButton;
+static MPoint s_mousePosition;
+
+// system mouse cursors
+static SDL_Cursor* s_standardCursor = NULL;
+static SDL_Cursor* s_handCursor = NULL;
+
+// for event loop
+static MBoolean s_isForeground = true;
+
+// for fade out / fade in
+static float s_fadeGamma = 1;
+
+// for checktyping
+typedef struct BufferedKey
+{
+ bool isASCII;
+
+ union
+ {
+ char ascii;
+ SDL_Keycode keycode;
+ } value;
+} BufferedKey;
+
+#define k_maxBufferedKeys 256
+
+static MBoolean s_interestedInTyping = false;
+static BufferedKey s_keyBuffer[k_maxBufferedKeys];
+static int s_keyBufferSize = 0;
+
+int SDLUi_EventFilter(void* junk, SDL_Event *event)
+{
+ (void) junk;
+
+ switch (event->type)
+ {
+ case SDL_TEXTINPUT:
+ {
+ // Put text input into a buffer.
+ if (s_interestedInTyping)
+ {
+ for (char* asciiPtr = event->text.text; *asciiPtr; ++asciiPtr)
+ {
+ BufferedKey key;
+ key.isASCII = true;
+ key.value.ascii = *asciiPtr;
+ s_keyBuffer[s_keyBufferSize] = key;
+ s_keyBufferSize = MinInt(k_maxBufferedKeys, s_keyBufferSize + 1);
+ }
+ }
+ break;
+ }
+
+ case SDL_KEYDOWN:
+ {
+ // Put keydowns in a buffer
+ if (s_interestedInTyping)
+ {
+ BufferedKey key;
+ key.isASCII = false;
+ key.value.keycode = event->key.keysym.sym;
+ s_keyBuffer[s_keyBufferSize] = key;
+ s_keyBufferSize = MinInt(k_maxBufferedKeys, s_keyBufferSize + 1);
+ }
+ break;
+ }
+
+ // Get mouse state
+ case SDL_MOUSEBUTTONDOWN:
+ {
+ if( event->button.button == SDL_BUTTON_LEFT )
+ s_mouseButton = true;
+
+ s_mousePosition.v = event->button.y;
+ s_mousePosition.h = event->button.x;
+ break;
+ }
+
+ case SDL_MOUSEBUTTONUP:
+ {
+ if( event->button.button == SDL_BUTTON_LEFT )
+ s_mouseButton = false;
+
+ s_mousePosition.v = event->button.y;
+ s_mousePosition.h = event->button.x;
+ break;
+ }
+
+ case SDL_MOUSEMOTION:
+ {
+ s_mousePosition.v = event->motion.y;
+ s_mousePosition.h = event->motion.x;
+ s_mouseButton = event->motion.state & SDL_BUTTON(1);
+ break;
+ }
+
+ case SDL_QUIT:
+ {
+ finished = true;
+ break;
+ }
+
+ case SDL_WINDOWEVENT:
+ {
+ if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST && s_isForeground)
+ {
+ FreezeGameTickCount();
+ //EnableMusic(false);
+ s_isForeground = false;
+ }
+ else if (event->window.event == SDL_WINDOWEVENT_FOCUS_GAINED && !s_isForeground)
+ {
+ UnfreezeGameTickCount();
+ //EnableMusic(musicOn);
+ s_isForeground = true;
+
+ DoFullRepaint();
+ }
+ else if (event->window.event == SDL_WINDOWEVENT_RESIZED)
+ {
+ SDLU_CreateRendererTexture();
+ }
+ break;
+ }
+ }
+
+ return 1;
+}
+
+
+void SDLU_CreateRendererTexture()
+{
+ if (!g_renderer)
+ return;
+
+ if (!crispUpscaling)
+ {
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
+ SDL_RenderSetIntegerScale(g_renderer, SDL_FALSE);
+ }
+ else
+ {
+ int minWidth = 640;
+ int minHeight = widescreen ? 360 : 480;
+
+ int currentWidth = 0;
+ int currentHeight = 0;
+#if SDL_VERSION_ATLEAST(2,26,0)
+ SDL_GetWindowSizeInPixels(g_window, ¤tWidth, ¤tHeight);
+#else
+ SDL_GetWindowSize(g_window, ¤tWidth, ¤tHeight);
+#endif
+
+ if (currentWidth < minWidth || currentHeight < minHeight)
+ {
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
+ SDL_RenderSetIntegerScale(g_renderer, SDL_FALSE);
+ }
+ else
+ {
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
+ SDL_RenderSetIntegerScale(g_renderer, SDL_TRUE);
+ }
+ }
+
+ if (g_windowTexture)
+ SDL_DestroyTexture(g_windowTexture);
+
+ g_windowTexture = SDL_CreateTexture(g_renderer,
+ SDL_PIXELFORMAT_RGB888,
+ SDL_TEXTUREACCESS_STREAMING,
+ 640, 480);
+
+ SDL_RenderSetLogicalSize(g_renderer, 640, widescreen ? 360: 480);
+}
+
+
+void SDLU_Init()
+{
+ SDL_SetEventFilter(SDLUi_EventFilter, NULL);
+
+ // Initialize eight bit grayscale ramp palette.
+ SDL_Color grayscaleColors[256];
+ for (int index=0; index<256; index++)
+ {
+ grayscaleColors[index].r =
+ grayscaleColors[index].g =
+ grayscaleColors[index].b = 255 - index;
+ grayscaleColors[index].a = 255;
+ }
+
+ s_grayscalePalette = SDL_AllocPalette(256);
+ SDL_SetPaletteColors(s_grayscalePalette, grayscaleColors, 0, arrsize(grayscaleColors));
+
+ s_standardCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
+ s_handCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
+}
+
+
+SDL_Rect* SDLU_MRectToSDLRect( const MRect* in, SDL_Rect* out )
+{
+ int t = in->top, l = in->left, b = in->bottom, r = in->right;
+
+ out->x = l;
+ out->y = t;
+ out->w = r - l;
+ out->h = b - t;
+
+ return out;
+}
+
+
+MRect* SDLU_SDLRectToMRect( const SDL_Rect* in, MRect* out )
+{
+ int x = in->x, y = in->y, w = in->w, h = in->h;
+
+ out->top = y;
+ out->left = x;
+ out->bottom = y + h;
+ out->right = x + w;
+
+ return out;
+}
+
+
+int SDLU_BlitSurface( SDL_Surface* src, SDL_Rect* srcrect,
+ SDL_Surface* dst, SDL_Rect* dstrect )
+{
+ // Let SDL handle this.
+ return SDL_BlitSurface( src, srcrect,
+ dst, dstrect );
+}
+
+
+void SDLU_GetPixel( SDL_Surface* surface, int x, int y, SDL_Color* pixel )
+{
+ unsigned int px;
+ unsigned char* ptr;
+
+ switch( surface->format->BytesPerPixel )
+ {
+ case 1:
+ ptr = (unsigned char*)surface->pixels + (y * surface->pitch) + (x);
+ px = *(unsigned char*) ptr;
+ break;
+
+ case 2:
+ ptr = (unsigned char*)surface->pixels + (y * surface->pitch) + (x * 2);
+ px = *(unsigned short*) ptr;
+ break;
+
+ case 4:
+ ptr = (unsigned char*)surface->pixels + (y * surface->pitch) + (x * 4);
+ px = *(unsigned int *) ptr;
+ break;
+
+ default:
+ Error("SDLU_GetPixel: unrecognized surface format");
+ return;
+ }
+
+ return SDL_GetRGB( px, surface->format, &pixel->r, &pixel->g, &pixel->b );
+}
+
+
+void SDLU_ChangeSurfaceDepth( SDL_Surface** surface, int depth )
+{
+ SDL_Surface* newSurface;
+
+ newSurface = SDLU_InitSurface( &surface[0]->clip_rect, depth );
+
+ SDLU_BlitSurface( *surface, &surface[0]->clip_rect,
+ newSurface, &newSurface->clip_rect );
+
+ SDL_FreeSurface( *surface );
+
+ *surface = newSurface;
+}
+
+
+SDL_Surface* SDLU_InitSurface( SDL_Rect* rect, int depth )
+{
+ SDL_Surface* surface = NULL;
+
+ switch( depth )
+ {
+ case 32:
+ surface = SDL_CreateRGBSurface(
+ SDL_SWSURFACE,
+ rect->w,
+ rect->h,
+ 32,
+ RED_MASK, GREEN_MASK, BLUE_MASK, 0);
+ break;
+
+ case 8:
+ surface = SDL_CreateRGBSurface(
+ SDL_SWSURFACE,
+ rect->w,
+ rect->h,
+ 8,
+ 0, 0, 0, 0 );
+
+ SDL_SetSurfacePalette(surface, s_grayscalePalette);
+ break;
+
+ default:
+ Error("SDLU_InitSurface: invalid depth");
+ return NULL;
+ }
+
+ if( surface == NULL )
+ {
+ Error( "SDLU_InitSurface: SDL_CreateRGBSurface" );
+ return NULL;
+ }
+
+ // SDL_FillRect only works on 8-bit or higher surfaces.
+ if( depth >= 8 )
+ SDL_FillRect( surface, rect, SDL_MapRGB( surface->format, 0xFF, 0xFF, 0xFF ) );
+
+ return surface;
+}
+
+
+void SDLU_BlitFrontSurface( SDL_Surface* source, SDL_Rect* sourceSDLRect, SDL_Rect* destSDLRect )
+{
+ SDLU_BlitSurface( source, sourceSDLRect,
+ g_frontSurface, destSDLRect );
+}
+
+
+void SDLU_SetBrightness( float b )
+{
+ s_fadeGamma = b;
+}
+
+void SDLU_Yield()
+{
+ SDL_Delay( 2 );
+ SDL_PumpEvents();
+}
+
+void SDLU_PumpEvents()
+{
+ static unsigned int lastPump = 0;
+ unsigned int time = MTickCount();
+
+ if( lastPump != time )
+ {
+ SDL_Event evt;
+ while( SDL_PollEvent( &evt ) ) { }
+ lastPump = time;
+ }
+}
+
+
+MBoolean SDLU_IsForeground()
+{
+ return s_isForeground;
+}
+
+
+void SDLU_StartWatchingTyping()
+{
+ s_interestedInTyping = true;
+ s_keyBufferSize = 0; // clear keybuffer
+}
+
+
+void SDLU_StopWatchingTyping()
+{
+ s_interestedInTyping = false;
+}
+
+
+MBoolean SDLU_CheckASCIITyping(char* ascii)
+{
+ if (s_keyBufferSize > 0 && s_keyBuffer[0].isASCII)
+ {
+ *ascii = s_keyBuffer[0].value.ascii;
+
+ s_keyBufferSize--;
+ SDL_memcpy(&s_keyBuffer[0], &s_keyBuffer[1], (s_keyBufferSize) * sizeof(BufferedKey));
+
+ return true;
+ }
+
+ *ascii = '\0';
+ return false;
+}
+
+
+MBoolean SDLU_CheckSDLTyping(SDL_Keycode* sdlKey)
+{
+ if (s_keyBufferSize > 0 && !s_keyBuffer[0].isASCII)
+ {
+ *sdlKey = s_keyBuffer[0].value.keycode;
+
+ s_keyBufferSize--;
+ SDL_memcpy(&s_keyBuffer[0], &s_keyBuffer[1], (s_keyBufferSize) * sizeof(BufferedKey));
+
+ return true;
+ }
+
+ *sdlKey = SDLK_UNKNOWN;
+ return false;
+}
+
+
+static MPoint SDLUi_TranslatePointFromWindowToFrontSurface(MPoint pt)
+{
+ // On macOS, the mouse position is relative to the window's "point size" on Retina screens.
+ int windowPointW = 1;
+ int windowPointH = 1;
+ int windowPixelW = 1;
+ int windowPixelH = 1;
+
+ SDL_GetWindowSize(g_window, &windowPointW, &windowPointH);
+#if SDL_VERSION_ATLEAST(2,26,0)
+ SDL_GetWindowSizeInPixels(g_window, &windowPixelW, &windowPixelH);
+#else
+ // Backwards compat with old versions of SDL
+ windowPixelW = windowPointW;
+ windowPixelH = windowPointH;
+#endif
+
+ if (windowPointW != windowPixelW || windowPointH != windowPixelH)
+ {
+ float dpiScaleX = (float) windowPixelW / (float) windowPointW; // gGameWindowWidth is in actual pixels
+ float dpiScaleY = (float) windowPixelH / (float) windowPointH; // gGameWindowHeight is in actual pixels
+ pt.h *= dpiScaleX;
+ pt.v *= dpiScaleY;
+ }
+
+ SDL_Rect viewport;
+ float scaleX, scaleY;
+ SDL_RenderGetViewport(g_renderer, &viewport);
+ SDL_RenderGetScale(g_renderer, &scaleX, &scaleY);
+
+ pt.h = pt.h / scaleX - viewport.x;
+ pt.v = pt.v / scaleY - viewport.y;
+
+ if (widescreen)
+ {
+ pt.h += g_widescreenCrop.x;
+ pt.v += g_widescreenCrop.y;
+ }
+
+ return pt;
+}
+
+
+void SDLU_GetMouse( MPoint* pt )
+{
+ SDLU_PumpEvents();
+ *pt = SDLUi_TranslatePointFromWindowToFrontSurface(s_mousePosition);
+}
+
+
+int SDLU_Button()
+{
+ SDLU_PumpEvents();
+ return s_mouseButton;
+}
+
+
+void SDLU_AcquireSurface( SDL_Surface* surface )
+{
+ if (s_acquireHead >= arrsize(s_acquireList) - 1)
+ Error("SDLU_AcquireSurface: overflow");
+
+ s_acquireList[++s_acquireHead] = surface;
+}
+
+
+SDL_Surface* SDLU_GetCurrentSurface()
+{
+ return s_acquireList[s_acquireHead];
+}
+
+
+void SDLU_ReleaseSurface( SDL_Surface* surface )
+{
+ if (s_acquireHead < 0)
+ Error( "SDLU_ReleaseSurface: underflow" );
+
+ if( s_acquireList[s_acquireHead] != surface )
+ Error( "SDLU_ReleaseSurface: out of order" );
+
+ s_acquireHead--;
+}
+
+
+void SDLU_Present()
+{
+ SDL_SetRenderDrawColor(g_renderer, 0, 0, 0, 255);
+
+ SDL_UpdateTexture(g_windowTexture, NULL, g_frontSurface->pixels, g_frontSurface->pitch);
+ SDL_RenderClear(g_renderer);
+
+ SDL_RenderCopy(g_renderer, g_windowTexture, widescreen ? &g_widescreenCrop : NULL, NULL);
+
+ if (s_fadeGamma < 1.0)
+ {
+ SDL_SetRenderDrawBlendMode(g_renderer, SDL_BLENDMODE_BLEND);
+ SDL_SetRenderDrawColor(g_renderer, 0, 0, 0, (Uint8)((1.0f - s_fadeGamma) * 255.0f));
+ SDL_RenderFillRect(g_renderer, NULL);
+ }
+
+ SDL_RenderPresent(g_renderer);
+
+#if 0
+ static int s_fpsAccumulator = 0;
+ static int s_fpsSampleStart = 0;
+ const int k_fpsSampleInterval = 500;
+
+ s_fpsAccumulator++;
+ int now = SDL_GetTicks();
+ int elapsed = now - s_fpsSampleStart;
+ if (elapsed > k_fpsSampleInterval)
+ {
+ float fps = s_fpsAccumulator / (elapsed / 1000.0f);
+#if _DEBUG
+ printf("FPS: %.1f\n", fps);
+#endif
+ s_fpsAccumulator = 0;
+ s_fpsSampleStart = now;
+ }
+#endif
+}
+
+
+void SDLU_SetSystemCursor(int which)
+{
+#if USE_CURSOR_SPRITE
+ SDL_ShowCursor(SDL_DISABLE);
+#else
+ switch (which)
+ {
+ case SYSTEM_CURSOR_OFF:
+ SDL_ShowCursor(SDL_DISABLE);
+ SDL_SetCursor(s_standardCursor);
+ break;
+
+ case SYSTEM_CURSOR_ARROW:
+ SDL_SetCursor(s_standardCursor);
+ SDL_ShowCursor(SDL_ENABLE);
+ break;
+
+ case SYSTEM_CURSOR_HAND:
+ SDL_SetCursor(s_handCursor);
+ SDL_ShowCursor(SDL_ENABLE);
+ break;
+ }
+#endif
+}
--- a/src/SDLU.cpp
+++ /dev/null
@@ -1,572 +1,0 @@
-///
-/// SDLU.c
-///
-/// SDL utilities.
-///
-/// John Stiles, 2002/10/12
-///
-
-#include "SDLU.h"
-#include "gameticks.h"
-#include "music.h"
-
-#include "main.h" // for Error
-#include <deque>
-
-using std::deque;
-
-// for acquiresurface
-const int k_acquireMax = 10;
-static int s_acquireHead = -1;
-static SDL_Surface* s_acquireList[k_acquireMax];
-
-// for initsurface
-static SDL_Palette* s_grayscalePalette;
-
-// for button and getmouse
-static int s_mouseButton;
-static MPoint s_mousePosition;
-
-// system mouse cursors
-static SDL_Cursor* s_standardCursor = NULL;
-static SDL_Cursor* s_handCursor = NULL;
-
-// for event loop
-static MBoolean s_isForeground = true;
-
-// for fade out / fade in
-static float s_fadeGamma = 1;
-
-// for checktyping
-struct BufferedKey
-{
- bool isASCII;
-
- union
- {
- char ascii;
- SDL_Keycode keycode;
- } value;
-};
-
-
-static MBoolean s_interestedInTyping = false;
-static std::deque<BufferedKey> s_keyBuffer;
-
-int SDLUi_EventFilter(void*, SDL_Event *event)
-{
- switch (event->type)
- {
- case SDL_TEXTINPUT:
- {
- // Put text input into a buffer.
- if (s_interestedInTyping)
- {
- for (char* asciiPtr = event->text.text; *asciiPtr; ++asciiPtr)
- {
- BufferedKey key;
- key.isASCII = true;
- key.value.ascii = *asciiPtr;
- s_keyBuffer.push_back(key);
- }
- }
- break;
- }
-
- case SDL_KEYDOWN:
- {
- // Put keydowns in a buffer
- if (s_interestedInTyping)
- {
- BufferedKey key;
- key.isASCII = false;
- key.value.keycode = event->key.keysym.sym;
- s_keyBuffer.push_back(key);
- }
- break;
- }
-
- // Get mouse state
- case SDL_MOUSEBUTTONDOWN:
- {
- if( event->button.button == SDL_BUTTON_LEFT )
- s_mouseButton = true;
-
- s_mousePosition.v = event->button.y;
- s_mousePosition.h = event->button.x;
- break;
- }
-
- case SDL_MOUSEBUTTONUP:
- {
- if( event->button.button == SDL_BUTTON_LEFT )
- s_mouseButton = false;
-
- s_mousePosition.v = event->button.y;
- s_mousePosition.h = event->button.x;
- break;
- }
-
- case SDL_MOUSEMOTION:
- {
- s_mousePosition.v = event->motion.y;
- s_mousePosition.h = event->motion.x;
- s_mouseButton = event->motion.state & SDL_BUTTON(1);
- break;
- }
-
- case SDL_QUIT:
- {
- finished = true;
- break;
- }
-
- case SDL_WINDOWEVENT:
- {
- if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST && s_isForeground)
- {
- FreezeGameTickCount();
- //EnableMusic(false);
- s_isForeground = false;
- }
- else if (event->window.event == SDL_WINDOWEVENT_FOCUS_GAINED && !s_isForeground)
- {
- UnfreezeGameTickCount();
- //EnableMusic(musicOn);
- s_isForeground = true;
-
- DoFullRepaint();
- }
- else if (event->window.event == SDL_WINDOWEVENT_RESIZED)
- {
- SDLU_CreateRendererTexture();
- }
- break;
- }
- }
-
- return 1;
-}
-
-
-void SDLU_CreateRendererTexture()
-{
- if (!g_renderer)
- return;
-
- if (!crispUpscaling)
- {
- SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
- SDL_RenderSetIntegerScale(g_renderer, SDL_FALSE);
- }
- else
- {
- int minWidth = 640;
- int minHeight = widescreen ? 360 : 480;
-
- int currentWidth = 0;
- int currentHeight = 0;
-#if SDL_VERSION_ATLEAST(2,26,0)
- SDL_GetWindowSizeInPixels(g_window, ¤tWidth, ¤tHeight);
-#else
- SDL_GetWindowSize(g_window, ¤tWidth, ¤tHeight);
-#endif
-
- if (currentWidth < minWidth || currentHeight < minHeight)
- {
- SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
- SDL_RenderSetIntegerScale(g_renderer, SDL_FALSE);
- }
- else
- {
- SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
- SDL_RenderSetIntegerScale(g_renderer, SDL_TRUE);
- }
- }
-
- if (g_windowTexture)
- SDL_DestroyTexture(g_windowTexture);
-
- g_windowTexture = SDL_CreateTexture(g_renderer,
- SDL_PIXELFORMAT_RGB888,
- SDL_TEXTUREACCESS_STREAMING,
- 640, 480);
-
- SDL_RenderSetLogicalSize(g_renderer, 640, widescreen ? 360: 480);
-}
-
-
-void SDLU_Init()
-{
- SDL_SetEventFilter(SDLUi_EventFilter, NULL);
-
- // Initialize eight bit grayscale ramp palette.
- SDL_Color grayscaleColors[256];
- for (int index=0; index<256; index++)
- {
- grayscaleColors[index].r =
- grayscaleColors[index].g =
- grayscaleColors[index].b = 255 - index;
- grayscaleColors[index].a = 255;
- }
-
- s_grayscalePalette = SDL_AllocPalette(256);
- SDL_SetPaletteColors(s_grayscalePalette, grayscaleColors, 0, arrsize(grayscaleColors));
-
- s_standardCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
- s_handCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
-}
-
-
-SDL_Rect* SDLU_MRectToSDLRect( const MRect* in, SDL_Rect* out )
-{
- int t = in->top, l = in->left, b = in->bottom, r = in->right;
-
- out->x = l;
- out->y = t;
- out->w = r - l;
- out->h = b - t;
-
- return out;
-}
-
-
-MRect* SDLU_SDLRectToMRect( const SDL_Rect* in, MRect* out )
-{
- int x = in->x, y = in->y, w = in->w, h = in->h;
-
- out->top = y;
- out->left = x;
- out->bottom = y + h;
- out->right = x + w;
-
- return out;
-}
-
-
-int SDLU_BlitSurface( SDL_Surface* src, SDL_Rect* srcrect,
- SDL_Surface* dst, SDL_Rect* dstrect )
-{
- // Let SDL handle this.
- return SDL_BlitSurface( src, srcrect,
- dst, dstrect );
-}
-
-
-void SDLU_GetPixel( SDL_Surface* surface, int x, int y, SDL_Color* pixel )
-{
- unsigned int px;
- unsigned char* ptr;
-
- switch( surface->format->BytesPerPixel )
- {
- case 1:
- ptr = (unsigned char*)surface->pixels + (y * surface->pitch) + (x);
- px = *(unsigned char*) ptr;
- break;
-
- case 2:
- ptr = (unsigned char*)surface->pixels + (y * surface->pitch) + (x * 2);
- px = *(unsigned short*) ptr;
- break;
-
- case 4:
- ptr = (unsigned char*)surface->pixels + (y * surface->pitch) + (x * 4);
- px = *(unsigned int *) ptr;
- break;
-
- default:
- Error("SDLU_GetPixel: unrecognized surface format");
- return;
- }
-
- return SDL_GetRGB( px, surface->format, &pixel->r, &pixel->g, &pixel->b );
-}
-
-
-void SDLU_ChangeSurfaceDepth( SDL_Surface** surface, int depth )
-{
- SDL_Surface* newSurface;
-
- newSurface = SDLU_InitSurface( &surface[0]->clip_rect, depth );
-
- SDLU_BlitSurface( *surface, &surface[0]->clip_rect,
- newSurface, &newSurface->clip_rect );
-
- SDL_FreeSurface( *surface );
-
- *surface = newSurface;
-}
-
-
-SDL_Surface* SDLU_InitSurface( SDL_Rect* rect, int depth )
-{
- SDL_Surface* surface = NULL;
-
- switch( depth )
- {
- case 32:
- surface = SDL_CreateRGBSurface(
- SDL_SWSURFACE,
- rect->w,
- rect->h,
- 32,
- RED_MASK, GREEN_MASK, BLUE_MASK, 0);
- break;
-
- case 8:
- surface = SDL_CreateRGBSurface(
- SDL_SWSURFACE,
- rect->w,
- rect->h,
- 8,
- 0, 0, 0, 0 );
-
- SDL_SetSurfacePalette(surface, s_grayscalePalette);
- break;
-
- default:
- Error("SDLU_InitSurface: invalid depth");
- return NULL;
- }
-
- if( surface == NULL )
- {
- Error( "SDLU_InitSurface: SDL_CreateRGBSurface" );
- return NULL;
- }
-
- // SDL_FillRect only works on 8-bit or higher surfaces.
- if( depth >= 8 )
- SDL_FillRect( surface, rect, SDL_MapRGB( surface->format, 0xFF, 0xFF, 0xFF ) );
-
- return surface;
-}
-
-
-void SDLU_BlitFrontSurface( SDL_Surface* source, SDL_Rect* sourceSDLRect, SDL_Rect* destSDLRect )
-{
- SDLU_BlitSurface( source, sourceSDLRect,
- g_frontSurface, destSDLRect );
-}
-
-
-void SDLU_SetBrightness( float b )
-{
- s_fadeGamma = b;
-}
-
-void SDLU_Yield()
-{
- SDL_Delay( 2 );
- SDL_PumpEvents();
-}
-
-void SDLU_PumpEvents()
-{
- static unsigned int lastPump = 0;
- unsigned int time = MTickCount();
-
- if( lastPump != time )
- {
- SDL_Event evt;
- while( SDL_PollEvent( &evt ) ) { }
- lastPump = time;
- }
-}
-
-
-MBoolean SDLU_IsForeground()
-{
- return s_isForeground;
-}
-
-
-void SDLU_StartWatchingTyping()
-{
- s_interestedInTyping = true;
- s_keyBuffer.clear();
-}
-
-
-void SDLU_StopWatchingTyping()
-{
- s_interestedInTyping = false;
-}
-
-
-MBoolean SDLU_CheckASCIITyping(char* ascii)
-{
- if (!s_keyBuffer.empty() && s_keyBuffer.front().isASCII)
- {
- *ascii = s_keyBuffer.front().value.ascii;
- s_keyBuffer.pop_front();
- return true;
- }
-
- *ascii = '\0';
- return false;
-}
-
-
-MBoolean SDLU_CheckSDLTyping(SDL_Keycode* sdlKey)
-{
- if (!s_keyBuffer.empty() && !s_keyBuffer.front().isASCII)
- {
- *sdlKey = s_keyBuffer.front().value.keycode;
- s_keyBuffer.pop_front();
- return true;
- }
-
- *sdlKey = SDLK_UNKNOWN;
- return false;
-}
-
-
-static MPoint SDLUi_TranslatePointFromWindowToFrontSurface(MPoint pt)
-{
- // On macOS, the mouse position is relative to the window's "point size" on Retina screens.
- int windowPointW = 1;
- int windowPointH = 1;
- int windowPixelW = 1;
- int windowPixelH = 1;
-
- SDL_GetWindowSize(g_window, &windowPointW, &windowPointH);
-#if SDL_VERSION_ATLEAST(2,26,0)
- SDL_GetWindowSizeInPixels(g_window, &windowPixelW, &windowPixelH);
-#else
- // Backwards compat with old versions of SDL
- windowPixelW = windowPointW;
- windowPixelH = windowPointH;
-#endif
-
- if (windowPointW != windowPixelW || windowPointH != windowPixelH)
- {
- float dpiScaleX = (float) windowPixelW / (float) windowPointW; // gGameWindowWidth is in actual pixels
- float dpiScaleY = (float) windowPixelH / (float) windowPointH; // gGameWindowHeight is in actual pixels
- pt.h *= dpiScaleX;
- pt.v *= dpiScaleY;
- }
-
- SDL_Rect viewport;
- float scaleX, scaleY;
- SDL_RenderGetViewport(g_renderer, &viewport);
- SDL_RenderGetScale(g_renderer, &scaleX, &scaleY);
-
- pt.h = pt.h / scaleX - viewport.x;
- pt.v = pt.v / scaleY - viewport.y;
-
- if (widescreen)
- {
- pt.h += g_widescreenCrop.x;
- pt.v += g_widescreenCrop.y;
- }
-
- return pt;
-}
-
-
-void SDLU_GetMouse( MPoint* pt )
-{
- SDLU_PumpEvents();
- *pt = SDLUi_TranslatePointFromWindowToFrontSurface(s_mousePosition);
-}
-
-
-int SDLU_Button()
-{
- SDLU_PumpEvents();
- return s_mouseButton;
-}
-
-
-void SDLU_AcquireSurface( SDL_Surface* surface )
-{
- if (s_acquireHead >= arrsize(s_acquireList) - 1)
- Error("SDLU_AcquireSurface: overflow");
-
- s_acquireList[++s_acquireHead] = surface;
-}
-
-
-SDL_Surface* SDLU_GetCurrentSurface()
-{
- return s_acquireList[s_acquireHead];
-}
-
-
-void SDLU_ReleaseSurface( SDL_Surface* surface )
-{
- if (s_acquireHead < 0)
- Error( "SDLU_ReleaseSurface: underflow" );
-
- if( s_acquireList[s_acquireHead] != surface )
- Error( "SDLU_ReleaseSurface: out of order" );
-
- s_acquireHead--;
-}
-
-
-void SDLU_Present()
-{
- SDL_SetRenderDrawColor(g_renderer, 0, 0, 0, 255);
-
- SDL_UpdateTexture(g_windowTexture, NULL, g_frontSurface->pixels, g_frontSurface->pitch);
- SDL_RenderClear(g_renderer);
-
- SDL_RenderCopy(g_renderer, g_windowTexture, widescreen ? &g_widescreenCrop : NULL, NULL);
-
- if (s_fadeGamma < 1.0)
- {
- SDL_SetRenderDrawBlendMode(g_renderer, SDL_BLENDMODE_BLEND);
- SDL_SetRenderDrawColor(g_renderer, 0, 0, 0, (Uint8)((1.0f - s_fadeGamma) * 255.0f));
- SDL_RenderFillRect(g_renderer, NULL);
- }
-
- SDL_RenderPresent(g_renderer);
-
-#if 0
- static int s_fpsAccumulator = 0;
- static int s_fpsSampleStart = 0;
- const int k_fpsSampleInterval = 500;
-
- s_fpsAccumulator++;
- int now = SDL_GetTicks();
- int elapsed = now - s_fpsSampleStart;
- if (elapsed > k_fpsSampleInterval)
- {
- float fps = s_fpsAccumulator / (elapsed / 1000.0f);
-#if _DEBUG
- printf("FPS: %.1f\n", fps);
-#endif
- s_fpsAccumulator = 0;
- s_fpsSampleStart = now;
- }
-#endif
-}
-
-
-void SDLU_SetSystemCursor(int which)
-{
-#if USE_CURSOR_SPRITE
- SDL_ShowCursor(SDL_DISABLE);
-#else
- switch (which)
- {
- case SYSTEM_CURSOR_OFF:
- SDL_ShowCursor(SDL_DISABLE);
- SDL_SetCursor(s_standardCursor);
- break;
-
- case SYSTEM_CURSOR_ARROW:
- SDL_SetCursor(s_standardCursor);
- SDL_ShowCursor(SDL_ENABLE);
- break;
-
- case SYSTEM_CURSOR_HAND:
- SDL_SetCursor(s_handCursor);
- SDL_ShowCursor(SDL_ENABLE);
- break;
- }
-#endif
-}
--- /dev/null
+++ b/src/blitter.c
@@ -1,0 +1,870 @@
+// blitter.c
+
+#include "SDLU.h"
+
+#include "main.h"
+#include "gworld.h"
+#include "blitter.h"
+#include "font.h"
+#include "level.h"
+#include "graphics.h"
+
+MBoolean update[2][kGridAcross][kGridDown];
+MBoolean refresh[2];
+
+void InitBlitter( void )
+{
+ int player, x, y;
+
+ for( player=0; player<=1; player++ )
+ {
+ refresh[player] = false;
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ update[player][x][y] = false;
+ }
+ }
+ }
+}
+
+void UpdatePlayerWindow( int player )
+{
+ SDL_Rect fullSDLRect, offsetSDLRect;
+ int x, y;
+
+ if( control[player] == kNobodyControl ) return;
+
+ if( playerWindowVisible[player] && refresh[player] )
+ {
+ MRect updateRect = {0, 0, 0, 0}, fullRect, offsetRect;
+ MBoolean first = true;
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=1; y<kGridDown; y++ )
+ {
+ if( update[player][x][y] )
+ {
+ updateRect.top = y * kBlobVertSize;
+ updateRect.left = x * kBlobHorizSize;
+ updateRect.bottom = updateRect.top + kBlobVertSize;
+ updateRect.right = updateRect.left + kBlobHorizSize;
+ if( first )
+ {
+ fullRect = updateRect;
+ first = false;
+ }
+ else
+ {
+ UnionMRect( &fullRect, &updateRect, &fullRect );
+ }
+
+ update[player][x][y] = false;
+ }
+ }
+ }
+
+ if( !first )
+ {
+ offsetRect = fullRect;
+ OffsetMRect( &offsetRect, playerWindowRect[player].left, playerWindowRect[player].top - kBlobVertSize );
+
+ SDLU_BlitFrontSurface( playerSpriteSurface[player],
+ SDLU_MRectToSDLRect( &fullRect, &fullSDLRect ),
+ SDLU_MRectToSDLRect( &offsetRect, &offsetSDLRect ) );
+ }
+ }
+}
+
+void SetUpdateRect( int player, MRect *where )
+{
+ int x,y;
+ int xMin, xMax, yMin, yMax;
+
+ xMin = where->left / kBlobHorizSize;
+ xMax = ( where->right + kBlobHorizSize - 1 ) / kBlobHorizSize;
+
+ if( xMin < 0 ) xMin = 0;
+ if( xMin > (kGridAcross-1) ) xMin = kGridAcross-1;
+ if( xMax < 0 ) xMax = 0;
+ if( xMax > kGridAcross ) xMax = kGridAcross;
+
+ yMin = where->top / kBlobVertSize;
+ yMax = ( where->bottom + kBlobVertSize - 1 ) / kBlobVertSize;
+
+ if( yMin < 0 ) yMin = 0;
+ if( yMin > (kGridDown-1) ) yMin = kGridDown-1;
+ if( yMax < 0 ) yMax = 0;
+ if( yMax > kGridDown ) yMax = kGridDown;
+
+ for( x=xMin; x<xMax; x++ )
+ {
+ for( y=yMin; y<yMax; y++ )
+ {
+ update[player][x][y] = true;
+ }
+ }
+
+ refresh[player] = true;
+}
+
+
+void SurfaceBlitMask( SDL_Surface* object, SDL_Surface* mask, SDL_Surface* dest,
+ const MRect* objectRect, const MRect* maskRect, const MRect* destRect )
+{
+ int startX = 0, startY = 0, endX, endY, x, y, srcRowBytes, mskRowBytes, dstRowBytes;
+ unsigned char *src, *msk, *dst;
+ MRect destBounds;
+
+ SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
+
+ endX = objectRect->right - objectRect->left;
+ endY = objectRect->bottom - objectRect->top;
+
+ if( destRect->left > destBounds.right || // completely clipped?
+ destRect->right < destBounds.left ||
+ destRect->top > destBounds.bottom ||
+ destRect->bottom < destBounds.top )
+ {
+ return; // do nothing
+ }
+
+ src = (unsigned char*) object->pixels;
+ msk = (unsigned char*) mask->pixels;
+ dst = (unsigned char*) dest->pixels;
+ srcRowBytes = object->pitch;
+ mskRowBytes = mask->pitch;
+ dstRowBytes = dest->pitch;
+
+ src += (objectRect->top * srcRowBytes) + (objectRect->left * BYTES_PER_PIXEL);
+ msk += (maskRect->top * mskRowBytes) + (maskRect->left * BYTES_PER_MASK_PIXEL);
+ dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
+
+ if( destRect->left < destBounds.left ) startX -= destRect->left - destBounds.left;
+ if( destRect->right > destBounds.right ) endX -= destRect->right - destBounds.right;
+ if( destRect->top < destBounds.top ) startY -= destRect->top - destBounds.top;
+ if( destRect->bottom > destBounds.bottom ) endY -= destRect->bottom - destBounds.bottom;
+
+ msk += (mskRowBytes * startY) + (startX * BYTES_PER_MASK_PIXEL);
+ src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+ dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+
+ for( y=startY; y<endY; y++ )
+ {
+ unsigned char *tSrc = src, *tDst = dst, *tMsk = msk;
+
+ for( x=startX; x<endX; x++ )
+ {
+ if( *msk )
+ {
+ *(COLOR_T*)dst = *(COLOR_T*)src;
+ }
+
+ src += BYTES_PER_PIXEL;
+ dst += BYTES_PER_PIXEL;
+ msk += BYTES_PER_MASK_PIXEL;
+ }
+
+ src = tSrc + srcRowBytes;
+ dst = tDst + dstRowBytes;
+ msk = tMsk + mskRowBytes;
+ }
+}
+
+
+void SurfaceBlitBlob( const MRect* blobRect, const MRect* destRect )
+{
+ SurfaceBlitMask( blobSurface, maskSurface, SDLU_GetCurrentSurface(),
+ blobRect, blobRect, destRect );
+}
+
+
+void SurfaceBlitColor( SDL_Surface* mask, SDL_Surface* dest,
+ const MRect* maskRect, const MRect* destRect,
+ int r, int g, int b, int weight )
+{
+ int startX = 0, startY = 0, endX, endY, x, y, mskRowBytes, dstRowBytes;
+ unsigned char *msk, *dst;
+ MRect destBounds;
+
+ endX = maskRect->right - maskRect->left;
+ endY = maskRect->bottom - maskRect->top;
+
+ SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
+
+ if( destRect->left > destBounds.right || // completely clipped?
+ destRect->right < destBounds.left ||
+ destRect->top > destBounds.bottom ||
+ destRect->bottom < destBounds.top )
+ {
+ return; // do nothing
+ }
+
+ msk = (unsigned char*) mask->pixels;
+ dst = (unsigned char*) dest->pixels;
+ mskRowBytes = mask->pitch;
+ dstRowBytes = dest->pitch;
+
+ msk += (maskRect->top * mskRowBytes) + (maskRect->left * BYTES_PER_MASK_PIXEL);
+ dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
+
+ if( destRect->left < destBounds.left ) startX -= destRect->left - destBounds.left;
+ if( destRect->right > destBounds.right ) endX -= destRect->right - destBounds.right;
+ if( destRect->top < destBounds.top ) startY -= destRect->top - destBounds.top;
+ if( destRect->bottom > destBounds.bottom ) endY -= destRect->bottom - destBounds.bottom;
+
+ msk += (mskRowBytes * startY) + (startX * BYTES_PER_MASK_PIXEL);
+ dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+
+ r *= weight;
+ g *= weight;
+ b *= weight;
+ weight = FULL_WEIGHT - weight;
+
+ for( y=startY; y<endY; y++ )
+ {
+ unsigned char *tMsk = msk, *tDst = dst;
+ int work, workB, workG, workR;
+
+ for( x=startX; x<endX; x++ )
+ {
+ if( *msk )
+ {
+ work = *(COLOR_T*)dst;
+ workB = ((((work ) & CHANNEL_MASK)*weight) + b) >> BITS_PER_1CHANNEL;
+ workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK)*weight) + g) ;
+ workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK)*weight) + r) << BITS_PER_1CHANNEL;
+
+ *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
+ }
+
+ dst += BYTES_PER_PIXEL;
+ msk += BYTES_PER_MASK_PIXEL;
+ }
+
+ msk = tMsk + mskRowBytes;
+ dst = tDst + dstRowBytes;
+ }
+}
+
+
+void SurfaceBlitAlpha( SDL_Surface* back, SDL_Surface* source, SDL_Surface* alpha, SDL_Surface* dest,
+ const MRect* backRect, const MRect* sourceRect, const MRect* alphaRect, const MRect* destRect )
+{
+ int startX = 0, startY = 0, endX, endY, x, y, srcRowBytes, alfRowBytes, dstRowBytes, bckRowBytes;
+ unsigned char *bck, *src, *alf, *dst;
+ MRect destBounds;
+
+ endX = sourceRect->right - sourceRect->left;
+ endY = sourceRect->bottom - sourceRect->top;
+
+ SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
+
+ if( destRect->left > destBounds.right || // completely clipped?
+ destRect->right < destBounds.left ||
+ destRect->top > destBounds.bottom ||
+ destRect->bottom < destBounds.top )
+ {
+ return; // do nothing
+ }
+
+ bck = (unsigned char*) back->pixels;
+ src = (unsigned char*) source->pixels;
+ alf = (unsigned char*) alpha->pixels;
+ dst = (unsigned char*) dest->pixels;
+ bckRowBytes = back->pitch;
+ srcRowBytes = source->pitch;
+ alfRowBytes = alpha->pitch;
+ dstRowBytes = dest->pitch;
+
+ bck += (backRect->top * bckRowBytes) + (backRect->left * BYTES_PER_PIXEL);
+ src += (sourceRect->top * srcRowBytes) + (sourceRect->left * BYTES_PER_PIXEL);
+ alf += (alphaRect->top * alfRowBytes) + (alphaRect->left * BYTES_PER_PIXEL);
+ dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
+
+ if( destRect->left < destBounds.left ) startX -= destRect->left - destBounds.left;
+ if( destRect->right > destBounds.right ) endX -= destRect->right - destBounds.right;
+ if( destRect->top < destBounds.top ) startY -= destRect->top - destBounds.top;
+ if( destRect->bottom > destBounds.bottom ) endY -= destRect->bottom - destBounds.bottom;
+
+ bck += (bckRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+ src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+ alf += (alfRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+ dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+
+ for( y=startY; y<endY; y++ )
+ {
+ unsigned char *tSrc = src, *tAlf = alf, *tDst = dst, *tBck = bck;
+ int pixS, pixB, weightS, weightB, workB, workG, workR;
+
+ for( x=startX; x<endX; x++ )
+ {
+ weightB = *(COLOR_T*)alf;
+
+ if( (weightB & (RED_MASK | GREEN_MASK | BLUE_MASK)) == (RED_MASK | GREEN_MASK | BLUE_MASK))
+ {
+ *(COLOR_T*)dst = *(COLOR_T*)bck;
+ }
+ else if( (weightB & (RED_MASK | GREEN_MASK | BLUE_MASK)) == 0)
+ {
+ *(COLOR_T*)dst = *(COLOR_T*)src;
+ }
+ else
+ {
+ weightS = ~weightB;
+
+ pixS = *(COLOR_T*)src;
+ pixB = *(COLOR_T*)bck;
+
+ workB = ((((pixS ) & CHANNEL_MASK) * ((weightS ) & CHANNEL_MASK)) + (((pixB ) & CHANNEL_MASK) * ((weightB ) & CHANNEL_MASK))) >> BITS_PER_1CHANNEL;
+ workG = ((((pixS >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * ((weightS >> BITS_PER_1CHANNEL ) & CHANNEL_MASK)) + (((pixB >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * ((weightB >> BITS_PER_1CHANNEL ) & CHANNEL_MASK)));
+ workR = ((((pixS >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * ((weightS >> BITS_PER_2CHANNELS) & CHANNEL_MASK)) + (((pixB >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * ((weightB >> BITS_PER_2CHANNELS) & CHANNEL_MASK))) << BITS_PER_1CHANNEL;
+
+ *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
+ }
+
+ src += BYTES_PER_PIXEL;
+ alf += BYTES_PER_PIXEL;
+ bck += BYTES_PER_PIXEL;
+ dst += BYTES_PER_PIXEL;
+ }
+
+ bck = tBck + bckRowBytes;
+ src = tSrc + srcRowBytes;
+ alf = tAlf + alfRowBytes;
+ dst = tDst + dstRowBytes;
+ }
+}
+
+
+void SurfaceBlitWeightedDualAlpha(SDL_Surface* back, SDL_Surface* source, SDL_Surface* mask, SDL_Surface* alpha, SDL_Surface* dest,
+ const MRect* backRect, const MRect* sourceRect, const MRect* maskRect, const MRect* alphaRect, const MRect* destRect,
+ int inWeight )
+{
+ int startX = 0, startY = 0, endX, endY, x, y,
+ srcRowBytes, alfRowBytes, mskRowBytes, dstRowBytes, bckRowBytes;
+ unsigned char *bck, *src, *alf, *msk, *dst;
+ MRect destBounds;
+
+ endX = sourceRect->right - sourceRect->left;
+ endY = sourceRect->bottom - sourceRect->top;
+
+ SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
+
+ if( destRect->left > destBounds.right || // completely clipped?
+ destRect->right < destBounds.left ||
+ destRect->top > destBounds.bottom ||
+ destRect->bottom < destBounds.top )
+ {
+ return; // do nothing
+ }
+
+ bck = (unsigned char*) back->pixels;
+ src = (unsigned char*) source->pixels;
+ msk = (unsigned char*) mask->pixels;
+ alf = (unsigned char*) alpha->pixels;
+ dst = (unsigned char*) dest->pixels;
+
+ bckRowBytes = back->pitch;
+ srcRowBytes = source->pitch;
+ mskRowBytes = mask->pitch;
+ alfRowBytes = alpha->pitch;
+ dstRowBytes = dest->pitch;
+
+ bck += (backRect->top * bckRowBytes) + (backRect->left * BYTES_PER_PIXEL);
+ src += (sourceRect->top * srcRowBytes) + (sourceRect->left * BYTES_PER_PIXEL);
+ alf += (alphaRect->top * alfRowBytes) + (alphaRect->left * BYTES_PER_PIXEL);
+ dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
+ msk += (maskRect->top * mskRowBytes) + (maskRect->left * BYTES_PER_MASK_PIXEL);
+
+ if( destRect->left < destBounds.left ) startX -= destRect->left - destBounds.left;
+ if( destRect->right > destBounds.right ) endX -= destRect->right - destBounds.right;
+ if( destRect->top < destBounds.top ) startY -= destRect->top - destBounds.top;
+ if( destRect->bottom > destBounds.bottom ) endY -= destRect->bottom - destBounds.bottom;
+
+ bck += (bckRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+ src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+ alf += (alfRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+ dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+ msk += (mskRowBytes * startY) + (startX * BYTES_PER_MASK_PIXEL);
+
+ for( y=startY; y<endY; y++ )
+ {
+ unsigned char *tSrc = src, *tAlf = alf, *tDst = dst, *tBck = bck, *tMsk = msk;
+ int pixS, pixB, weightS, weightB, work, workB, workG, workR;
+
+ for( x=startX; x<endX; x++ )
+ {
+ if( *msk )
+ {
+ work = *(COLOR_T*)alf;
+ workB = ((((work ) & CHANNEL_MASK)*inWeight) ) >> BITS_PER_1CHANNEL;
+ workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK)*inWeight) );
+ workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK)*inWeight) ) << BITS_PER_1CHANNEL;
+
+ weightB = ~((workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK));
+
+ if( (weightB & (RED_MASK | GREEN_MASK | BLUE_MASK)) == (RED_MASK | GREEN_MASK | BLUE_MASK))
+ {
+ *(COLOR_T*)dst = *(COLOR_T*)bck;
+ }
+ else if( (weightB & (RED_MASK | GREEN_MASK | BLUE_MASK)) == 0)
+ {
+ *(COLOR_T*)dst = *(COLOR_T*)src;
+ }
+ else
+ {
+ weightS = ~weightB;
+
+ pixS = *(COLOR_T*)src;
+ pixB = *(COLOR_T*)bck;
+
+ workB = ((((pixS ) & CHANNEL_MASK) * ((weightS ) & CHANNEL_MASK)) + (((pixB ) & CHANNEL_MASK) * ((weightB ) & CHANNEL_MASK))) >> BITS_PER_1CHANNEL;
+ workG = ((((pixS >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * ((weightS >> BITS_PER_1CHANNEL ) & CHANNEL_MASK)) + (((pixB >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * ((weightB >> BITS_PER_1CHANNEL ) & CHANNEL_MASK)));
+ workR = ((((pixS >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * ((weightS >> BITS_PER_2CHANNELS) & CHANNEL_MASK)) + (((pixB >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * ((weightB >> BITS_PER_2CHANNELS) & CHANNEL_MASK))) << BITS_PER_1CHANNEL;
+
+ *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
+ }
+ }
+
+ src += BYTES_PER_PIXEL;
+ alf += BYTES_PER_PIXEL;
+ bck += BYTES_PER_PIXEL;
+ dst += BYTES_PER_PIXEL;
+ msk += BYTES_PER_MASK_PIXEL;
+ }
+
+ bck = tBck + bckRowBytes;
+ src = tSrc + srcRowBytes;
+ alf = tAlf + alfRowBytes;
+ dst = tDst + dstRowBytes;
+ msk = tMsk + mskRowBytes;
+ }
+}
+
+void SurfaceBlitWeightedCharacter( SkittlesFontPtr font, unsigned char text, MPoint *dPoint, int r, int g, int b, int alpha )
+{
+ if (alpha == FULL_WEIGHT)
+ {
+ SurfaceBlitCharacter( font, text, dPoint, r, g, b, 0 );
+ return;
+ }
+
+ if (alpha == 0)
+ {
+ return;
+ }
+
+ SDL_Surface* destSurface;
+ unsigned char* src;
+ unsigned char* dst;
+ int srcRowBytes;
+ int dstRowBytes;
+ int index;
+ MRect destBounds;
+
+ int height = font->surface->h;
+ int width = font->width[text];
+ int across = font->across[text];
+
+ destSurface = SDLU_GetCurrentSurface();
+ SDLU_SDLRectToMRect( &destSurface->clip_rect, &destBounds );
+
+ if( (dPoint->h + width) > destBounds.right || // clipped?
+ (dPoint->v + height) > destBounds.bottom ||
+ dPoint->h < destBounds.left ||
+ dPoint->v < destBounds.top )
+ {
+ dPoint->h += width;
+ return; // do nothing
+ }
+
+ srcRowBytes = font->surface->pitch;
+ dstRowBytes = destSurface->pitch;
+
+ src = (unsigned char*) font->surface->pixels + across;
+ dst = (unsigned char*) destSurface->pixels + (dPoint->h * BYTES_PER_PIXEL) + (dPoint->v * dstRowBytes);
+
+ while( height-- )
+ {
+ unsigned char *tSrc = src, *tDst = dst;
+
+ for( index=0; index<width; index++ )
+ {
+ int workR, workG, workB, work, weightS, weightD;
+ weightS = *src & CHANNEL_MASK;
+
+ weightS = (weightS * alpha) >> BITS_PER_1CHANNEL;
+
+ if( weightS )
+ {
+ weightD = FULL_WEIGHT - weightS;
+
+ work = *(COLOR_T*)dst;
+ workB = ((((work ) & CHANNEL_MASK) * weightD) + (b * weightS)) >> BITS_PER_1CHANNEL;
+ workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weightD) + (g * weightS));
+ workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK) * weightD) + (r * weightS)) << BITS_PER_1CHANNEL;
+
+ *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
+ }
+
+ src++;
+ dst+=BYTES_PER_PIXEL;
+ }
+
+ src = tSrc + srcRowBytes;
+ dst = tDst + dstRowBytes;
+ }
+
+ dPoint->h += width;
+}
+
+void SurfaceBlitCharacter( SkittlesFontPtr font, unsigned char text, MPoint *dPoint, int r, int g, int b, int dropShadow )
+{
+ SDL_Surface* destSurface;
+ unsigned char* src;
+ unsigned char* dst;
+ int srcRowBytes;
+ int dstRowBytes;
+ int index;
+ int rgbPremixed;
+ MRect destBounds;
+
+ int height = font->surface->h;
+ int width = font->width[text];
+ int across = font->across[text];
+
+ destSurface = SDLU_GetCurrentSurface();
+ SDLU_SDLRectToMRect( &destSurface->clip_rect, &destBounds );
+
+ if( (dPoint->h + width) > destBounds.right || // clipped?
+ (dPoint->v + height) > destBounds.bottom ||
+ dPoint->h < destBounds.left ||
+ dPoint->v < destBounds.top )
+ {
+ dPoint->h += width;
+ return; // do nothing
+ }
+
+ srcRowBytes = font->surface->pitch;
+ dstRowBytes = destSurface->pitch;
+
+ src = (unsigned char*) font->surface->pixels + across;
+ dst = (unsigned char*) destSurface->pixels + (dPoint->h * BYTES_PER_PIXEL) + (dPoint->v * dstRowBytes);
+ rgbPremixed = (r << BITS_PER_2CHANNELS) | (g << BITS_PER_1CHANNEL) | b;
+
+ switch( dropShadow )
+ {
+ case 0:
+ while( height-- )
+ {
+ unsigned char *tSrc = src, *tDst = dst;
+
+ for( index=0; index<width; index++ )
+ {
+ int workR, workG, workB, work, weightS, weightD;
+ weightS = *src & CHANNEL_MASK;
+
+ if( weightS == CHANNEL_MASK )
+ {
+ *(COLOR_T*)dst = rgbPremixed;
+ }
+ else if( weightS > 0 )
+ {
+ weightD = FULL_WEIGHT - weightS;
+
+ work = *(COLOR_T*)dst;
+ workB = ((((work ) & CHANNEL_MASK) * weightD) + (b * weightS)) >> BITS_PER_1CHANNEL;
+ workG = ((((work >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weightD) + (g * weightS));
+ workR = ((((work >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * weightD) + (r * weightS)) << BITS_PER_1CHANNEL;
+
+ *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
+ }
+
+ src++;
+ dst+=BYTES_PER_PIXEL;
+ }
+
+ src = tSrc + srcRowBytes;
+ dst = tDst + dstRowBytes;
+ }
+ break;
+
+ default:
+ {
+ unsigned char *drp = dst + ((dstRowBytes + BYTES_PER_PIXEL) * dropShadow);
+
+ while( height-- )
+ {
+ unsigned char *tSrc = src, *tDst = dst, *tDrp = drp;
+
+ for( index=0; index<width; index++ )
+ {
+ int workR, workG, workB, work, weightS, weightD;
+ weightS = *src & CHANNEL_MASK;
+
+ if( weightS == CHANNEL_MASK )
+ {
+ *(COLOR_T*)drp = 0;
+ *(COLOR_T*)dst = rgbPremixed;
+ }
+ else if( weightS > 0 )
+ {
+ weightD = FULL_WEIGHT - weightS;
+
+ work = *(COLOR_T*)drp;
+ workB = ((((work ) & CHANNEL_MASK) * weightD)) >> BITS_PER_1CHANNEL;
+ workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weightD));
+ workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK) * weightD)) << BITS_PER_1CHANNEL;
+ *(COLOR_T*)drp = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
+
+ work = *(COLOR_T*)dst;
+ workB = ((((work ) & CHANNEL_MASK) * weightD) + (b * weightS)) >> BITS_PER_1CHANNEL;
+ workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weightD) + (g * weightS));
+ workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK) * weightD) + (r * weightS)) << BITS_PER_1CHANNEL;
+ *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
+ }
+
+ src++;
+ dst+=BYTES_PER_PIXEL;
+ drp+=BYTES_PER_PIXEL;
+ }
+
+ src = tSrc + srcRowBytes;
+ dst = tDst + dstRowBytes;
+ drp = tDrp + dstRowBytes;
+ }
+ break;
+ }
+ }
+ dPoint->h += width;
+}
+
+void SurfaceBlitColorOver( SDL_Surface* source, SDL_Surface* dest,
+ const MRect* sourceRect, const MRect* destRect,
+ int r, int g, int b, int weight )
+{
+ int startX = 0, startY = 0, endX, endY, x, y, dstRowBytes, srcRowBytes;
+ unsigned char* src;
+ unsigned char* dst;
+ MRect destBounds;
+
+ SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
+
+ endX = destRect->right - destRect->left;
+ endY = destRect->bottom - destRect->top;
+
+ if( destRect->left > destBounds.right || // completely clipped?
+ destRect->right < destBounds.left ||
+ destRect->top > destBounds.bottom ||
+ destRect->bottom < destBounds.top )
+ {
+ return; // do nothing
+ }
+
+ src = (unsigned char*) source->pixels;
+ dst = (unsigned char*) dest->pixels;
+ srcRowBytes = source->pitch;
+ dstRowBytes = dest->pitch;
+
+ src += (sourceRect->top * srcRowBytes) + (sourceRect->left * BYTES_PER_PIXEL);
+ dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
+
+ if( destRect->left < destBounds.left ) startX -= destRect->left - destBounds.left;
+ if( destRect->right > destBounds.right ) endX -= destRect->right - destBounds.right;
+ if( destRect->top < destBounds.top ) startY -= destRect->top - destBounds.top;
+ if( destRect->bottom > destBounds.bottom ) endY -= destRect->bottom - destBounds.bottom;
+
+ src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+ dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+
+ r *= weight;
+ g *= weight;
+ b *= weight;
+ weight = FULL_WEIGHT - weight;
+
+ for( y=startY; y<endY; y++ )
+ {
+ unsigned char *tSrc = src, *tDst = dst;
+ int work, workB, workG, workR;
+
+ for( x=startX; x<endX; x++ )
+ {
+ work = *(COLOR_T*)src;
+ workB = ((((work ) & CHANNEL_MASK)*weight) + b) >> BITS_PER_1CHANNEL;
+ workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK)*weight) + g);
+ workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK)*weight) + r) << BITS_PER_1CHANNEL;
+
+ *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
+
+ src += BYTES_PER_PIXEL;
+ dst += BYTES_PER_PIXEL;
+ }
+
+ src = tSrc + srcRowBytes;
+ dst = tDst + dstRowBytes;
+ }
+}
+
+// NOTE: due to rounding error, there should never be a case of transitioning all the way from 0 to 255.
+// You'll overflow and get weird glitches on the edges.
+
+void SurfaceBlitBlendOver(SDL_Surface* source, SDL_Surface* dest,
+ const MRect* sourceRect, const MRect* destRect,
+ int r1, int g1, int b1,
+ int r2, int g2, int b2,
+ int r3, int g3, int b3,
+ int r4, int g4, int b4,
+ int weight )
+{
+ int startX = 0, startY = 0, endX, endY, x, y;
+ int rA, gA, bA;
+ int rB, gB, bB;
+ int rI, gI, bI;
+ int vrLI, vgLI, vbLI;
+ int vrRI, vgRI, vbRI;
+ int weight12, ditherDiff;
+ int width, height, dstRowBytes, srcRowBytes;
+ unsigned char *src, *dst;
+ MRect destBounds;
+ MBoolean oddX = false;
+
+ SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
+
+ if( destRect->left > destBounds.right || // completely clipped?
+ destRect->right < destBounds.left ||
+ destRect->top > destBounds.bottom ||
+ destRect->bottom < destBounds.top )
+ {
+ return; // do nothing
+ }
+
+ endX = destRect->right - destRect->left;
+ endY = destRect->bottom - destRect->top;
+
+ src = (unsigned char*) source->pixels;
+ dst = (unsigned char*) dest->pixels;
+ srcRowBytes = source->pitch;
+ dstRowBytes = dest->pitch;
+
+ src += (sourceRect->top * srcRowBytes) + (sourceRect->left * BYTES_PER_PIXEL);
+ dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
+
+ if( destRect->left < destBounds.left ) startX -= destRect->left - destBounds.left;
+ if( destRect->right > destBounds.right ) endX -= destRect->right - destBounds.right;
+ if( destRect->top < destBounds.top ) startY -= destRect->top - destBounds.top;
+ if( destRect->bottom > destBounds.bottom ) endY -= destRect->bottom - destBounds.bottom;
+
+ src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+ dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
+
+ height = endY - startY;
+ width = endX - startX;
+
+ weight12 = weight << 12;
+
+ r1 *= weight12; g1 *= weight12; b1 *= weight12;
+ r2 *= weight12; g2 *= weight12; b2 *= weight12;
+ r3 *= weight12; g3 *= weight12; b3 *= weight12;
+ r4 *= weight12; g4 *= weight12; b4 *= weight12;
+ ditherDiff = weight12 >> 1;
+
+ vrLI = (r3 - r1) / height;
+ vgLI = (g3 - g1) / height;
+ vbLI = (b3 - b1) / height;
+
+ vrRI = (r4 - r2) / height;
+ vgRI = (g4 - g2) / height;
+ vbRI = (b4 - b2) / height;
+
+ weight = FULL_WEIGHT - weight;
+ weight12 = weight << 12;
+
+ if( (endX - startX) & 1 )
+ {
+ endX--;
+ oddX = true;
+ }
+
+ for( y=startY; y<endY; y++ )
+ {
+ unsigned char *tSrc = src, *tDst = dst;
+ int work, workB, workG, workR;
+
+ if( y & 1 )
+ {
+ rA = r1;
+ gA = g1;
+ bA = b1;
+ rB = r1 - ditherDiff; if( rB < 0 ) rB = 0;
+ gB = g1 - ditherDiff; if( gB < 0 ) gB = 0;
+ bB = b1 - ditherDiff; if( bB < 0 ) bB = 0;
+ }
+ else
+ {
+ rA = r1 - ditherDiff; if( rA < 0 ) rA = 0;
+ gA = g1 - ditherDiff; if( gA < 0 ) gA = 0;
+ bA = b1 - ditherDiff; if( bA < 0 ) bA = 0;
+ rB = r1;
+ gB = g1;
+ bB = b1;
+ }
+
+ rI = (2 * (r2 - r1)) / width;
+ gI = (2 * (g2 - g1)) / width;
+ bI = (2 * (b2 - b1)) / width;
+
+ for( x=startX; x<endX; x+=2 )
+ {
+ work = *(COLOR_T*)src;
+
+ workB = ((((work ) & CHANNEL_MASK) * weight12) + bA) >> (12 + BITS_PER_1CHANNEL);
+ workG = ((((work >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weight12) + gA) >> (12 );
+ workR = ((((work >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * weight12) + rA) >> (12 - BITS_PER_1CHANNEL);
+
+ *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
+
+ src+= BYTES_PER_PIXEL;
+ dst+= BYTES_PER_PIXEL;
+ rA += rI;
+ gA += gI;
+ bA += bI;
+
+ work = *(COLOR_T*)src;
+
+ workB = ((((work ) & CHANNEL_MASK) * weight12) + bB) >> (12 + BITS_PER_1CHANNEL);
+ workG = ((((work >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weight12) + gB) >> (12 );
+ workR = ((((work >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * weight12) + rB) >> (12 - BITS_PER_1CHANNEL);
+
+ *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
+
+ src+= BYTES_PER_PIXEL;
+ dst+= BYTES_PER_PIXEL;
+ rB += rI;
+ gB += gI;
+ bB += bI;
+ }
+
+ if( oddX )
+ {
+ work = *(COLOR_T*)src;
+
+ workB = ((((work ) & CHANNEL_MASK) * weight12) + bA) >> (12 + BITS_PER_1CHANNEL);
+ workG = ((((work >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weight12) + gA) >> (12 );
+ workR = ((((work >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * weight12) + rA) >> (12 - BITS_PER_1CHANNEL);
+
+ *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
+ }
+
+ src = tSrc + srcRowBytes;
+ dst = tDst + dstRowBytes;
+
+ r1 += vrLI; r2 += vrRI;
+ g1 += vgLI; g2 += vgRI;
+ b1 += vbLI; b2 += vbRI;
+ }
+}
+
--- a/src/blitter.cpp
+++ /dev/null
@@ -1,870 +1,0 @@
-// blitter.c
-
-#include "SDLU.h"
-
-#include "main.h"
-#include "gworld.h"
-#include "blitter.h"
-#include "font.h"
-#include "level.h"
-#include "graphics.h"
-
-MBoolean update[2][kGridAcross][kGridDown];
-MBoolean refresh[2];
-
-void InitBlitter( void )
-{
- int player, x, y;
-
- for( player=0; player<=1; player++ )
- {
- refresh[player] = false;
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- update[player][x][y] = false;
- }
- }
- }
-}
-
-void UpdatePlayerWindow( int player )
-{
- SDL_Rect fullSDLRect, offsetSDLRect;
- int x, y;
-
- if( control[player] == kNobodyControl ) return;
-
- if( playerWindowVisible[player] && refresh[player] )
- {
- MRect updateRect = {0, 0, 0, 0}, fullRect, offsetRect;
- MBoolean first = true;
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=1; y<kGridDown; y++ )
- {
- if( update[player][x][y] )
- {
- updateRect.top = y * kBlobVertSize;
- updateRect.left = x * kBlobHorizSize;
- updateRect.bottom = updateRect.top + kBlobVertSize;
- updateRect.right = updateRect.left + kBlobHorizSize;
- if( first )
- {
- fullRect = updateRect;
- first = false;
- }
- else
- {
- UnionMRect( &fullRect, &updateRect, &fullRect );
- }
-
- update[player][x][y] = false;
- }
- }
- }
-
- if( !first )
- {
- offsetRect = fullRect;
- OffsetMRect( &offsetRect, playerWindowRect[player].left, playerWindowRect[player].top - kBlobVertSize );
-
- SDLU_BlitFrontSurface( playerSpriteSurface[player],
- SDLU_MRectToSDLRect( &fullRect, &fullSDLRect ),
- SDLU_MRectToSDLRect( &offsetRect, &offsetSDLRect ) );
- }
- }
-}
-
-void SetUpdateRect( int player, MRect *where )
-{
- int x,y;
- int xMin, xMax, yMin, yMax;
-
- xMin = where->left / kBlobHorizSize;
- xMax = ( where->right + kBlobHorizSize - 1 ) / kBlobHorizSize;
-
- if( xMin < 0 ) xMin = 0;
- if( xMin > (kGridAcross-1) ) xMin = kGridAcross-1;
- if( xMax < 0 ) xMax = 0;
- if( xMax > kGridAcross ) xMax = kGridAcross;
-
- yMin = where->top / kBlobVertSize;
- yMax = ( where->bottom + kBlobVertSize - 1 ) / kBlobVertSize;
-
- if( yMin < 0 ) yMin = 0;
- if( yMin > (kGridDown-1) ) yMin = kGridDown-1;
- if( yMax < 0 ) yMax = 0;
- if( yMax > kGridDown ) yMax = kGridDown;
-
- for( x=xMin; x<xMax; x++ )
- {
- for( y=yMin; y<yMax; y++ )
- {
- update[player][x][y] = true;
- }
- }
-
- refresh[player] = true;
-}
-
-
-void SurfaceBlitMask( SDL_Surface* object, SDL_Surface* mask, SDL_Surface* dest,
- const MRect* objectRect, const MRect* maskRect, const MRect* destRect )
-{
- int startX = 0, startY = 0, endX, endY, x, y, srcRowBytes, mskRowBytes, dstRowBytes;
- unsigned char *src, *msk, *dst;
- MRect destBounds;
-
- SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
-
- endX = objectRect->right - objectRect->left;
- endY = objectRect->bottom - objectRect->top;
-
- if( destRect->left > destBounds.right || // completely clipped?
- destRect->right < destBounds.left ||
- destRect->top > destBounds.bottom ||
- destRect->bottom < destBounds.top )
- {
- return; // do nothing
- }
-
- src = (unsigned char*) object->pixels;
- msk = (unsigned char*) mask->pixels;
- dst = (unsigned char*) dest->pixels;
- srcRowBytes = object->pitch;
- mskRowBytes = mask->pitch;
- dstRowBytes = dest->pitch;
-
- src += (objectRect->top * srcRowBytes) + (objectRect->left * BYTES_PER_PIXEL);
- msk += (maskRect->top * mskRowBytes) + (maskRect->left * BYTES_PER_MASK_PIXEL);
- dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
-
- if( destRect->left < destBounds.left ) startX -= destRect->left - destBounds.left;
- if( destRect->right > destBounds.right ) endX -= destRect->right - destBounds.right;
- if( destRect->top < destBounds.top ) startY -= destRect->top - destBounds.top;
- if( destRect->bottom > destBounds.bottom ) endY -= destRect->bottom - destBounds.bottom;
-
- msk += (mskRowBytes * startY) + (startX * BYTES_PER_MASK_PIXEL);
- src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
- dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
-
- for( y=startY; y<endY; y++ )
- {
- unsigned char *tSrc = src, *tDst = dst, *tMsk = msk;
-
- for( x=startX; x<endX; x++ )
- {
- if( *msk )
- {
- *(COLOR_T*)dst = *(COLOR_T*)src;
- }
-
- src += BYTES_PER_PIXEL;
- dst += BYTES_PER_PIXEL;
- msk += BYTES_PER_MASK_PIXEL;
- }
-
- src = tSrc + srcRowBytes;
- dst = tDst + dstRowBytes;
- msk = tMsk + mskRowBytes;
- }
-}
-
-
-void SurfaceBlitBlob( const MRect* blobRect, const MRect* destRect )
-{
- SurfaceBlitMask( blobSurface, maskSurface, SDLU_GetCurrentSurface(),
- blobRect, blobRect, destRect );
-}
-
-
-void SurfaceBlitColor( SDL_Surface* mask, SDL_Surface* dest,
- const MRect* maskRect, const MRect* destRect,
- int r, int g, int b, int weight )
-{
- int startX = 0, startY = 0, endX, endY, x, y, mskRowBytes, dstRowBytes;
- unsigned char *msk, *dst;
- MRect destBounds;
-
- endX = maskRect->right - maskRect->left;
- endY = maskRect->bottom - maskRect->top;
-
- SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
-
- if( destRect->left > destBounds.right || // completely clipped?
- destRect->right < destBounds.left ||
- destRect->top > destBounds.bottom ||
- destRect->bottom < destBounds.top )
- {
- return; // do nothing
- }
-
- msk = (unsigned char*) mask->pixels;
- dst = (unsigned char*) dest->pixels;
- mskRowBytes = mask->pitch;
- dstRowBytes = dest->pitch;
-
- msk += (maskRect->top * mskRowBytes) + (maskRect->left * BYTES_PER_MASK_PIXEL);
- dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
-
- if( destRect->left < destBounds.left ) startX -= destRect->left - destBounds.left;
- if( destRect->right > destBounds.right ) endX -= destRect->right - destBounds.right;
- if( destRect->top < destBounds.top ) startY -= destRect->top - destBounds.top;
- if( destRect->bottom > destBounds.bottom ) endY -= destRect->bottom - destBounds.bottom;
-
- msk += (mskRowBytes * startY) + (startX * BYTES_PER_MASK_PIXEL);
- dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
-
- r *= weight;
- g *= weight;
- b *= weight;
- weight = FULL_WEIGHT - weight;
-
- for( y=startY; y<endY; y++ )
- {
- unsigned char *tMsk = msk, *tDst = dst;
- int work, workB, workG, workR;
-
- for( x=startX; x<endX; x++ )
- {
- if( *msk )
- {
- work = *(COLOR_T*)dst;
- workB = ((((work ) & CHANNEL_MASK)*weight) + b) >> BITS_PER_1CHANNEL;
- workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK)*weight) + g) ;
- workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK)*weight) + r) << BITS_PER_1CHANNEL;
-
- *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
- }
-
- dst += BYTES_PER_PIXEL;
- msk += BYTES_PER_MASK_PIXEL;
- }
-
- msk = tMsk + mskRowBytes;
- dst = tDst + dstRowBytes;
- }
-}
-
-
-void SurfaceBlitAlpha( SDL_Surface* back, SDL_Surface* source, SDL_Surface* alpha, SDL_Surface* dest,
- const MRect* backRect, const MRect* sourceRect, const MRect* alphaRect, const MRect* destRect )
-{
- int startX = 0, startY = 0, endX, endY, x, y, srcRowBytes, alfRowBytes, dstRowBytes, bckRowBytes;
- unsigned char *bck, *src, *alf, *dst;
- MRect destBounds;
-
- endX = sourceRect->right - sourceRect->left;
- endY = sourceRect->bottom - sourceRect->top;
-
- SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
-
- if( destRect->left > destBounds.right || // completely clipped?
- destRect->right < destBounds.left ||
- destRect->top > destBounds.bottom ||
- destRect->bottom < destBounds.top )
- {
- return; // do nothing
- }
-
- bck = (unsigned char*) back->pixels;
- src = (unsigned char*) source->pixels;
- alf = (unsigned char*) alpha->pixels;
- dst = (unsigned char*) dest->pixels;
- bckRowBytes = back->pitch;
- srcRowBytes = source->pitch;
- alfRowBytes = alpha->pitch;
- dstRowBytes = dest->pitch;
-
- bck += (backRect->top * bckRowBytes) + (backRect->left * BYTES_PER_PIXEL);
- src += (sourceRect->top * srcRowBytes) + (sourceRect->left * BYTES_PER_PIXEL);
- alf += (alphaRect->top * alfRowBytes) + (alphaRect->left * BYTES_PER_PIXEL);
- dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
-
- if( destRect->left < destBounds.left ) startX -= destRect->left - destBounds.left;
- if( destRect->right > destBounds.right ) endX -= destRect->right - destBounds.right;
- if( destRect->top < destBounds.top ) startY -= destRect->top - destBounds.top;
- if( destRect->bottom > destBounds.bottom ) endY -= destRect->bottom - destBounds.bottom;
-
- bck += (bckRowBytes * startY) + (startX * BYTES_PER_PIXEL);
- src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
- alf += (alfRowBytes * startY) + (startX * BYTES_PER_PIXEL);
- dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
-
- for( y=startY; y<endY; y++ )
- {
- unsigned char *tSrc = src, *tAlf = alf, *tDst = dst, *tBck = bck;
- int pixS, pixB, weightS, weightB, workB, workG, workR;
-
- for( x=startX; x<endX; x++ )
- {
- weightB = *(COLOR_T*)alf;
-
- if( (weightB & (RED_MASK | GREEN_MASK | BLUE_MASK)) == (RED_MASK | GREEN_MASK | BLUE_MASK))
- {
- *(COLOR_T*)dst = *(COLOR_T*)bck;
- }
- else if( (weightB & (RED_MASK | GREEN_MASK | BLUE_MASK)) == 0)
- {
- *(COLOR_T*)dst = *(COLOR_T*)src;
- }
- else
- {
- weightS = ~weightB;
-
- pixS = *(COLOR_T*)src;
- pixB = *(COLOR_T*)bck;
-
- workB = ((((pixS ) & CHANNEL_MASK) * ((weightS ) & CHANNEL_MASK)) + (((pixB ) & CHANNEL_MASK) * ((weightB ) & CHANNEL_MASK))) >> BITS_PER_1CHANNEL;
- workG = ((((pixS >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * ((weightS >> BITS_PER_1CHANNEL ) & CHANNEL_MASK)) + (((pixB >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * ((weightB >> BITS_PER_1CHANNEL ) & CHANNEL_MASK)));
- workR = ((((pixS >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * ((weightS >> BITS_PER_2CHANNELS) & CHANNEL_MASK)) + (((pixB >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * ((weightB >> BITS_PER_2CHANNELS) & CHANNEL_MASK))) << BITS_PER_1CHANNEL;
-
- *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
- }
-
- src += BYTES_PER_PIXEL;
- alf += BYTES_PER_PIXEL;
- bck += BYTES_PER_PIXEL;
- dst += BYTES_PER_PIXEL;
- }
-
- bck = tBck + bckRowBytes;
- src = tSrc + srcRowBytes;
- alf = tAlf + alfRowBytes;
- dst = tDst + dstRowBytes;
- }
-}
-
-
-void SurfaceBlitWeightedDualAlpha(SDL_Surface* back, SDL_Surface* source, SDL_Surface* mask, SDL_Surface* alpha, SDL_Surface* dest,
- const MRect* backRect, const MRect* sourceRect, const MRect* maskRect, const MRect* alphaRect, const MRect* destRect,
- int inWeight )
-{
- int startX = 0, startY = 0, endX, endY, x, y,
- srcRowBytes, alfRowBytes, mskRowBytes, dstRowBytes, bckRowBytes;
- unsigned char *bck, *src, *alf, *msk, *dst;
- MRect destBounds;
-
- endX = sourceRect->right - sourceRect->left;
- endY = sourceRect->bottom - sourceRect->top;
-
- SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
-
- if( destRect->left > destBounds.right || // completely clipped?
- destRect->right < destBounds.left ||
- destRect->top > destBounds.bottom ||
- destRect->bottom < destBounds.top )
- {
- return; // do nothing
- }
-
- bck = (unsigned char*) back->pixels;
- src = (unsigned char*) source->pixels;
- msk = (unsigned char*) mask->pixels;
- alf = (unsigned char*) alpha->pixels;
- dst = (unsigned char*) dest->pixels;
-
- bckRowBytes = back->pitch;
- srcRowBytes = source->pitch;
- mskRowBytes = mask->pitch;
- alfRowBytes = alpha->pitch;
- dstRowBytes = dest->pitch;
-
- bck += (backRect->top * bckRowBytes) + (backRect->left * BYTES_PER_PIXEL);
- src += (sourceRect->top * srcRowBytes) + (sourceRect->left * BYTES_PER_PIXEL);
- alf += (alphaRect->top * alfRowBytes) + (alphaRect->left * BYTES_PER_PIXEL);
- dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
- msk += (maskRect->top * mskRowBytes) + (maskRect->left * BYTES_PER_MASK_PIXEL);
-
- if( destRect->left < destBounds.left ) startX -= destRect->left - destBounds.left;
- if( destRect->right > destBounds.right ) endX -= destRect->right - destBounds.right;
- if( destRect->top < destBounds.top ) startY -= destRect->top - destBounds.top;
- if( destRect->bottom > destBounds.bottom ) endY -= destRect->bottom - destBounds.bottom;
-
- bck += (bckRowBytes * startY) + (startX * BYTES_PER_PIXEL);
- src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
- alf += (alfRowBytes * startY) + (startX * BYTES_PER_PIXEL);
- dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
- msk += (mskRowBytes * startY) + (startX * BYTES_PER_MASK_PIXEL);
-
- for( y=startY; y<endY; y++ )
- {
- unsigned char *tSrc = src, *tAlf = alf, *tDst = dst, *tBck = bck, *tMsk = msk;
- int pixS, pixB, weightS, weightB, work, workB, workG, workR;
-
- for( x=startX; x<endX; x++ )
- {
- if( *msk )
- {
- work = *(COLOR_T*)alf;
- workB = ((((work ) & CHANNEL_MASK)*inWeight) ) >> BITS_PER_1CHANNEL;
- workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK)*inWeight) );
- workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK)*inWeight) ) << BITS_PER_1CHANNEL;
-
- weightB = ~((workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK));
-
- if( (weightB & (RED_MASK | GREEN_MASK | BLUE_MASK)) == (RED_MASK | GREEN_MASK | BLUE_MASK))
- {
- *(COLOR_T*)dst = *(COLOR_T*)bck;
- }
- else if( (weightB & (RED_MASK | GREEN_MASK | BLUE_MASK)) == 0)
- {
- *(COLOR_T*)dst = *(COLOR_T*)src;
- }
- else
- {
- weightS = ~weightB;
-
- pixS = *(COLOR_T*)src;
- pixB = *(COLOR_T*)bck;
-
- workB = ((((pixS ) & CHANNEL_MASK) * ((weightS ) & CHANNEL_MASK)) + (((pixB ) & CHANNEL_MASK) * ((weightB ) & CHANNEL_MASK))) >> BITS_PER_1CHANNEL;
- workG = ((((pixS >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * ((weightS >> BITS_PER_1CHANNEL ) & CHANNEL_MASK)) + (((pixB >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * ((weightB >> BITS_PER_1CHANNEL ) & CHANNEL_MASK)));
- workR = ((((pixS >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * ((weightS >> BITS_PER_2CHANNELS) & CHANNEL_MASK)) + (((pixB >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * ((weightB >> BITS_PER_2CHANNELS) & CHANNEL_MASK))) << BITS_PER_1CHANNEL;
-
- *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
- }
- }
-
- src += BYTES_PER_PIXEL;
- alf += BYTES_PER_PIXEL;
- bck += BYTES_PER_PIXEL;
- dst += BYTES_PER_PIXEL;
- msk += BYTES_PER_MASK_PIXEL;
- }
-
- bck = tBck + bckRowBytes;
- src = tSrc + srcRowBytes;
- alf = tAlf + alfRowBytes;
- dst = tDst + dstRowBytes;
- msk = tMsk + mskRowBytes;
- }
-}
-
-void SurfaceBlitWeightedCharacter( SkittlesFontPtr font, unsigned char text, MPoint *dPoint, int r, int g, int b, int alpha )
-{
- if (alpha == FULL_WEIGHT)
- {
- SurfaceBlitCharacter( font, text, dPoint, r, g, b, 0 );
- return;
- }
-
- if (alpha == 0)
- {
- return;
- }
-
- SDL_Surface* destSurface;
- unsigned char* src;
- unsigned char* dst;
- int srcRowBytes;
- int dstRowBytes;
- int index;
- MRect destBounds;
-
- int height = font->surface->h;
- int width = font->width[text];
- int across = font->across[text];
-
- destSurface = SDLU_GetCurrentSurface();
- SDLU_SDLRectToMRect( &destSurface->clip_rect, &destBounds );
-
- if( (dPoint->h + width) > destBounds.right || // clipped?
- (dPoint->v + height) > destBounds.bottom ||
- dPoint->h < destBounds.left ||
- dPoint->v < destBounds.top )
- {
- dPoint->h += width;
- return; // do nothing
- }
-
- srcRowBytes = font->surface->pitch;
- dstRowBytes = destSurface->pitch;
-
- src = (unsigned char*) font->surface->pixels + across;
- dst = (unsigned char*) destSurface->pixels + (dPoint->h * BYTES_PER_PIXEL) + (dPoint->v * dstRowBytes);
-
- while( height-- )
- {
- unsigned char *tSrc = src, *tDst = dst;
-
- for( index=0; index<width; index++ )
- {
- int workR, workG, workB, work, weightS, weightD;
- weightS = *src & CHANNEL_MASK;
-
- weightS = (weightS * alpha) >> BITS_PER_1CHANNEL;
-
- if( weightS )
- {
- weightD = FULL_WEIGHT - weightS;
-
- work = *(COLOR_T*)dst;
- workB = ((((work ) & CHANNEL_MASK) * weightD) + (b * weightS)) >> BITS_PER_1CHANNEL;
- workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weightD) + (g * weightS));
- workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK) * weightD) + (r * weightS)) << BITS_PER_1CHANNEL;
-
- *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
- }
-
- src++;
- dst+=BYTES_PER_PIXEL;
- }
-
- src = tSrc + srcRowBytes;
- dst = tDst + dstRowBytes;
- }
-
- dPoint->h += width;
-}
-
-void SurfaceBlitCharacter( SkittlesFontPtr font, unsigned char text, MPoint *dPoint, int r, int g, int b, int dropShadow )
-{
- SDL_Surface* destSurface;
- unsigned char* src;
- unsigned char* dst;
- int srcRowBytes;
- int dstRowBytes;
- int index;
- int rgbPremixed;
- MRect destBounds;
-
- int height = font->surface->h;
- int width = font->width[text];
- int across = font->across[text];
-
- destSurface = SDLU_GetCurrentSurface();
- SDLU_SDLRectToMRect( &destSurface->clip_rect, &destBounds );
-
- if( (dPoint->h + width) > destBounds.right || // clipped?
- (dPoint->v + height) > destBounds.bottom ||
- dPoint->h < destBounds.left ||
- dPoint->v < destBounds.top )
- {
- dPoint->h += width;
- return; // do nothing
- }
-
- srcRowBytes = font->surface->pitch;
- dstRowBytes = destSurface->pitch;
-
- src = (unsigned char*) font->surface->pixels + across;
- dst = (unsigned char*) destSurface->pixels + (dPoint->h * BYTES_PER_PIXEL) + (dPoint->v * dstRowBytes);
- rgbPremixed = (r << BITS_PER_2CHANNELS) | (g << BITS_PER_1CHANNEL) | b;
-
- switch( dropShadow )
- {
- case 0:
- while( height-- )
- {
- unsigned char *tSrc = src, *tDst = dst;
-
- for( index=0; index<width; index++ )
- {
- int workR, workG, workB, work, weightS, weightD;
- weightS = *src & CHANNEL_MASK;
-
- if( weightS == CHANNEL_MASK )
- {
- *(COLOR_T*)dst = rgbPremixed;
- }
- else if( weightS > 0 )
- {
- weightD = FULL_WEIGHT - weightS;
-
- work = *(COLOR_T*)dst;
- workB = ((((work ) & CHANNEL_MASK) * weightD) + (b * weightS)) >> BITS_PER_1CHANNEL;
- workG = ((((work >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weightD) + (g * weightS));
- workR = ((((work >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * weightD) + (r * weightS)) << BITS_PER_1CHANNEL;
-
- *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
- }
-
- src++;
- dst+=BYTES_PER_PIXEL;
- }
-
- src = tSrc + srcRowBytes;
- dst = tDst + dstRowBytes;
- }
- break;
-
- default:
- {
- unsigned char *drp = dst + ((dstRowBytes + BYTES_PER_PIXEL) * dropShadow);
-
- while( height-- )
- {
- unsigned char *tSrc = src, *tDst = dst, *tDrp = drp;
-
- for( index=0; index<width; index++ )
- {
- int workR, workG, workB, work, weightS, weightD;
- weightS = *src & CHANNEL_MASK;
-
- if( weightS == CHANNEL_MASK )
- {
- *(COLOR_T*)drp = 0;
- *(COLOR_T*)dst = rgbPremixed;
- }
- else if( weightS > 0 )
- {
- weightD = FULL_WEIGHT - weightS;
-
- work = *(COLOR_T*)drp;
- workB = ((((work ) & CHANNEL_MASK) * weightD)) >> BITS_PER_1CHANNEL;
- workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weightD));
- workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK) * weightD)) << BITS_PER_1CHANNEL;
- *(COLOR_T*)drp = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
-
- work = *(COLOR_T*)dst;
- workB = ((((work ) & CHANNEL_MASK) * weightD) + (b * weightS)) >> BITS_PER_1CHANNEL;
- workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weightD) + (g * weightS));
- workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK) * weightD) + (r * weightS)) << BITS_PER_1CHANNEL;
- *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
- }
-
- src++;
- dst+=BYTES_PER_PIXEL;
- drp+=BYTES_PER_PIXEL;
- }
-
- src = tSrc + srcRowBytes;
- dst = tDst + dstRowBytes;
- drp = tDrp + dstRowBytes;
- }
- break;
- }
- }
- dPoint->h += width;
-}
-
-void SurfaceBlitColorOver( SDL_Surface* source, SDL_Surface* dest,
- const MRect* sourceRect, const MRect* destRect,
- int r, int g, int b, int weight )
-{
- int startX = 0, startY = 0, endX, endY, x, y, dstRowBytes, srcRowBytes;
- unsigned char* src;
- unsigned char* dst;
- MRect destBounds;
-
- SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
-
- endX = destRect->right - destRect->left;
- endY = destRect->bottom - destRect->top;
-
- if( destRect->left > destBounds.right || // completely clipped?
- destRect->right < destBounds.left ||
- destRect->top > destBounds.bottom ||
- destRect->bottom < destBounds.top )
- {
- return; // do nothing
- }
-
- src = (unsigned char*) source->pixels;
- dst = (unsigned char*) dest->pixels;
- srcRowBytes = source->pitch;
- dstRowBytes = dest->pitch;
-
- src += (sourceRect->top * srcRowBytes) + (sourceRect->left * BYTES_PER_PIXEL);
- dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
-
- if( destRect->left < destBounds.left ) startX -= destRect->left - destBounds.left;
- if( destRect->right > destBounds.right ) endX -= destRect->right - destBounds.right;
- if( destRect->top < destBounds.top ) startY -= destRect->top - destBounds.top;
- if( destRect->bottom > destBounds.bottom ) endY -= destRect->bottom - destBounds.bottom;
-
- src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
- dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
-
- r *= weight;
- g *= weight;
- b *= weight;
- weight = FULL_WEIGHT - weight;
-
- for( y=startY; y<endY; y++ )
- {
- unsigned char *tSrc = src, *tDst = dst;
- int work, workB, workG, workR;
-
- for( x=startX; x<endX; x++ )
- {
- work = *(COLOR_T*)src;
- workB = ((((work ) & CHANNEL_MASK)*weight) + b) >> BITS_PER_1CHANNEL;
- workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK)*weight) + g);
- workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK)*weight) + r) << BITS_PER_1CHANNEL;
-
- *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
-
- src += BYTES_PER_PIXEL;
- dst += BYTES_PER_PIXEL;
- }
-
- src = tSrc + srcRowBytes;
- dst = tDst + dstRowBytes;
- }
-}
-
-// NOTE: due to rounding error, there should never be a case of transitioning all the way from 0 to 255.
-// You'll overflow and get weird glitches on the edges.
-
-void SurfaceBlitBlendOver(SDL_Surface* source, SDL_Surface* dest,
- const MRect* sourceRect, const MRect* destRect,
- int r1, int g1, int b1,
- int r2, int g2, int b2,
- int r3, int g3, int b3,
- int r4, int g4, int b4,
- int weight )
-{
- int startX = 0, startY = 0, endX, endY, x, y;
- int rA, gA, bA;
- int rB, gB, bB;
- int rI, gI, bI;
- int vrLI, vgLI, vbLI;
- int vrRI, vgRI, vbRI;
- int weight12, ditherDiff;
- int width, height, dstRowBytes, srcRowBytes;
- unsigned char *src, *dst;
- MRect destBounds;
- MBoolean oddX = false;
-
- SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
-
- if( destRect->left > destBounds.right || // completely clipped?
- destRect->right < destBounds.left ||
- destRect->top > destBounds.bottom ||
- destRect->bottom < destBounds.top )
- {
- return; // do nothing
- }
-
- endX = destRect->right - destRect->left;
- endY = destRect->bottom - destRect->top;
-
- src = (unsigned char*) source->pixels;
- dst = (unsigned char*) dest->pixels;
- srcRowBytes = source->pitch;
- dstRowBytes = dest->pitch;
-
- src += (sourceRect->top * srcRowBytes) + (sourceRect->left * BYTES_PER_PIXEL);
- dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
-
- if( destRect->left < destBounds.left ) startX -= destRect->left - destBounds.left;
- if( destRect->right > destBounds.right ) endX -= destRect->right - destBounds.right;
- if( destRect->top < destBounds.top ) startY -= destRect->top - destBounds.top;
- if( destRect->bottom > destBounds.bottom ) endY -= destRect->bottom - destBounds.bottom;
-
- src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
- dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
-
- height = endY - startY;
- width = endX - startX;
-
- weight12 = weight << 12;
-
- r1 *= weight12; g1 *= weight12; b1 *= weight12;
- r2 *= weight12; g2 *= weight12; b2 *= weight12;
- r3 *= weight12; g3 *= weight12; b3 *= weight12;
- r4 *= weight12; g4 *= weight12; b4 *= weight12;
- ditherDiff = weight12 >> 1;
-
- vrLI = (r3 - r1) / height;
- vgLI = (g3 - g1) / height;
- vbLI = (b3 - b1) / height;
-
- vrRI = (r4 - r2) / height;
- vgRI = (g4 - g2) / height;
- vbRI = (b4 - b2) / height;
-
- weight = FULL_WEIGHT - weight;
- weight12 = weight << 12;
-
- if( (endX - startX) & 1 )
- {
- endX--;
- oddX = true;
- }
-
- for( y=startY; y<endY; y++ )
- {
- unsigned char *tSrc = src, *tDst = dst;
- int work, workB, workG, workR;
-
- if( y & 1 )
- {
- rA = r1;
- gA = g1;
- bA = b1;
- rB = r1 - ditherDiff; if( rB < 0 ) rB = 0;
- gB = g1 - ditherDiff; if( gB < 0 ) gB = 0;
- bB = b1 - ditherDiff; if( bB < 0 ) bB = 0;
- }
- else
- {
- rA = r1 - ditherDiff; if( rA < 0 ) rA = 0;
- gA = g1 - ditherDiff; if( gA < 0 ) gA = 0;
- bA = b1 - ditherDiff; if( bA < 0 ) bA = 0;
- rB = r1;
- gB = g1;
- bB = b1;
- }
-
- rI = (2 * (r2 - r1)) / width;
- gI = (2 * (g2 - g1)) / width;
- bI = (2 * (b2 - b1)) / width;
-
- for( x=startX; x<endX; x+=2 )
- {
- work = *(COLOR_T*)src;
-
- workB = ((((work ) & CHANNEL_MASK) * weight12) + bA) >> (12 + BITS_PER_1CHANNEL);
- workG = ((((work >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weight12) + gA) >> (12 );
- workR = ((((work >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * weight12) + rA) >> (12 - BITS_PER_1CHANNEL);
-
- *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
-
- src+= BYTES_PER_PIXEL;
- dst+= BYTES_PER_PIXEL;
- rA += rI;
- gA += gI;
- bA += bI;
-
- work = *(COLOR_T*)src;
-
- workB = ((((work ) & CHANNEL_MASK) * weight12) + bB) >> (12 + BITS_PER_1CHANNEL);
- workG = ((((work >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weight12) + gB) >> (12 );
- workR = ((((work >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * weight12) + rB) >> (12 - BITS_PER_1CHANNEL);
-
- *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
-
- src+= BYTES_PER_PIXEL;
- dst+= BYTES_PER_PIXEL;
- rB += rI;
- gB += gI;
- bB += bI;
- }
-
- if( oddX )
- {
- work = *(COLOR_T*)src;
-
- workB = ((((work ) & CHANNEL_MASK) * weight12) + bA) >> (12 + BITS_PER_1CHANNEL);
- workG = ((((work >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weight12) + gA) >> (12 );
- workR = ((((work >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * weight12) + rA) >> (12 - BITS_PER_1CHANNEL);
-
- *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
- }
-
- src = tSrc + srcRowBytes;
- dst = tDst + dstRowBytes;
-
- r1 += vrLI; r2 += vrRI;
- g1 += vgLI; g2 += vgRI;
- b1 += vbLI; b2 += vbRI;
- }
-}
-
--- /dev/null
+++ b/src/control.c
@@ -1,0 +1,629 @@
+// control.c
+
+#include "main.h"
+#include "control.h"
+#include "moving.h"
+#include "players.h"
+#include "random.h"
+#include "grays.h"
+#include "zap.h"
+#include "gameticks.h"
+#include "level.h"
+#include "tutorial.h"
+#include <stdlib.h>
+
+int destinationX[2], destinationR[2];
+signed char tempGrid[kGridAcross][kGridDown];
+MTicks timeAI[2], timeMove[2];
+MBoolean moveQuick[2];
+AutoPatternPtr autoPattern = NULL;
+
+void AutoControl( int player )
+{
+ if( autoPattern )
+ {
+ switch( autoPattern->command )
+ {
+ case kMessage:
+ StartBalloon( autoPattern->message );
+ autoPattern++;
+ break;
+
+ case kIdleTicks:
+ if( !tutorialTime )
+ {
+ tutorialTime = GameTickCount() + autoPattern->d1;
+ }
+ else
+ {
+ if( GameTickCount() >= tutorialTime )
+ {
+ tutorialTime = 0;
+ autoPattern++;
+ }
+ }
+ break;
+
+ case kRetrieve:
+ if( role[player] == kWaitForRetrieval )
+ {
+ nextA[player] = abs( autoPattern->d1 );
+ nextB[player] = abs( autoPattern->d2 );
+ nextM[player] = (autoPattern->d1 < 0);
+ nextG[player] = (autoPattern->d1 == kBombBottom) && (autoPattern->d2 == kBombTop);
+
+ if( !nextG[player] )
+ {
+ nextA[player] = pieceMap[ nextA[player] ];
+ nextB[player] = pieceMap[ nextB[player] ];
+ }
+
+ role[player] = kRetrieveBlobs;
+ autoPattern++;
+ }
+ break;
+
+ case kPosition:
+ if( (role[player] != kFalling) || (blobX[player] == autoPattern->d1) )
+ {
+ autoPattern++;
+ }
+ else if( GameTickCount() >= timeMove[player] )
+ {
+ timeMove[player] = GameTickCount() + 12;
+
+ if( blobX[player] > autoPattern->d1 )
+ {
+ if( CanGoLeft( player ) )
+ GoLeft( player );
+ }
+ else
+ {
+ if( CanGoRight( player ) )
+ GoRight( player );
+ }
+ }
+ break;
+
+ case kSpin:
+ if( role[player] != kFalling )
+ {
+ autoPattern++;
+ }
+ else if( CanRotate( player ) )
+ {
+ DoRotate( player );
+ autoPattern++;
+ }
+ break;
+
+ case kBlockUntilLand:
+ if( role[player] != kFalling )
+ {
+ autoPattern++;
+ }
+ break;
+
+ case kBlockUntilDrop:
+ if( !dropping[player] ) DoDrop( player );
+
+ if( role[player] != kFalling )
+ {
+ autoPattern++;
+ }
+ break;
+
+ case kPunish:
+ if( role[player] == kWaitForRetrieval )
+ {
+ lockGrays[player] = autoPattern->d1;
+ SetupGrays( player );
+ blobTime[player] = GameTickCount( );
+ role[player] = kDropGrays;
+
+ autoPattern++;
+ }
+ break;
+
+ case kComplete:
+ EndTutorial( );
+ break;
+
+ case kBlockUntilComplete:
+ if( role[player] == kWaitForRetrieval )
+ {
+ autoPattern++;
+ }
+ break;
+ }
+ }
+}
+
+void PlayerControl( int player )
+{
+ int a = player, b = player;
+ MBoolean moved = false;
+
+ if( players == 1 )
+ {
+ a = 0;
+ b = 1;
+ }
+
+ if( hitKey[a].left || hitKey[b].left )
+ {
+ if( GameTickCount() >= timeMove[player] )
+ {
+ timeMove[player] += 12;
+ if( CanGoLeft( player ) )
+ GoLeft( player );
+ }
+
+ moved = true;
+ }
+
+ if( hitKey[a].right || hitKey[b].right )
+ {
+ if( GameTickCount() >= timeMove[player] )
+ {
+ timeMove[player] += 12;
+ if( CanGoRight( player ) )
+ GoRight( player );
+ }
+
+ moved = true;
+ }
+
+ if( !moved ) timeMove[player] = GameTickCount( );
+
+ if( hitKey[a].rotate == 1 || hitKey[b].rotate == 1 )
+ {
+ if( CanRotate( player ) )
+ DoRotate( player );
+ }
+
+ if( hitKey[a].drop == 1 || hitKey[b].drop == 1 )
+ {
+ DoDrop( player );
+ }
+
+ if( hitKey[a].drop == 0 && hitKey[b].drop == 0 )
+ {
+ StopDrop( player );
+ }
+}
+
+void AIControl( int player )
+{
+ if( timeAI[player] > GameTickCount() )
+ return;
+
+ timeAI[player] += moveQuick[player]? character[player].speedRush:
+ character[player].speedNormal;
+
+ switch( RandomBefore( 2 ) )
+ {
+ case 0:
+ if( destinationR[player] != blobR[player] )
+ {
+ if( CanRotate(player) )
+ {
+ DoRotate( player );
+ }
+ }
+ break;
+
+ case 1:
+ if( destinationX[player] != blobX[player] )
+ {
+ if( destinationX[player] > blobX[player] )
+ {
+ if( CanGoRight( player ) )
+ GoRight( player );
+ }
+ else
+ {
+ if( CanGoLeft( player ) )
+ GoLeft( player );
+ }
+ }
+ break;
+ }
+
+ if( destinationX[player] == blobX[player] &&
+ destinationR[player] == blobR[player] &&
+ RandomBefore( 100 ) < character[player].intellect )
+ {
+ DoDrop( player );
+ }
+}
+
+void ChooseAIDestination( int player )
+{
+ int testX, testR, testX2, testR2, value, bestValue = -9999999;
+ int x, y;
+ int bestX[kGridAcross*4], bestR[kGridAcross*4], currentBest = -1;
+ int rowDifference, totalTries, temp;
+ MBoolean shouldTry[kGridAcross][4];
+
+ timeAI[player] = GameTickCount( ) + 1;
+ moveQuick[player] = true;
+
+ if( grenade[player] )
+ {
+ bestValue = 0;
+ currentBest = 2;
+
+ for( testX = 0; testX < kGridAcross; testX++ )
+ {
+ rowDifference = GetRowHeight( player, testX );
+
+ if( (rowDifference < kGridDown - 1) &&
+ (grid[player][testX][rowDifference+1] >= kFirstBlob) &&
+ (grid[player][testX][rowDifference+1] <= kLastBlob) )
+ {
+ value = 0;
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ if( grid[player][x][y] == grid[player][testX][rowDifference+1] ) value++;
+ }
+ }
+
+ if( value > bestValue )
+ {
+ bestValue = value;
+ currentBest = testX;
+ }
+ }
+ }
+
+ destinationR[player] = upRotate;
+ destinationX[player] = currentBest;
+ return;
+ }
+
+ if( (GameTickCount() - startTime) <= 3600 )
+ {
+ for( testX = 0; testX < kGridAcross; testX++ )
+ {
+ rowDifference = GetRowHeight( player, testX ) - character[player].autoSetup[testX];
+
+ if( rowDifference >= 2 )
+ {
+ destinationR[player] = downRotate;
+ destinationX[player] = testX;
+ return;
+ }
+
+ if( rowDifference == 1 )
+ {
+ destinationX[player] = testX;
+
+ if( testX > 0 )
+ {
+ if( GetRowHeight( player, testX-1 ) > character[player].autoSetup[testX-1] )
+ {
+ destinationR[player] = leftRotate;
+ return;
+ }
+ }
+
+ if( testX < (kGridAcross-1) )
+ {
+ if( GetRowHeight( player, testX+1 ) > character[player].autoSetup[testX+1] )
+ {
+ destinationR[player] = rightRotate;
+ return;
+ }
+ }
+
+ destinationR[player] = upRotate;
+ return;
+ }
+ }
+ }
+
+ moveQuick[player] = (emotions[player] == kEmotionSad) || (emotions[player] == kEmotionPanic);
+
+ totalTries = character[player].intellect;
+ for( testX = 0; testX < kGridAcross; testX++ )
+ {
+ for( testR = 0; testR < 4; testR++ )
+ {
+ shouldTry[testX][testR] = --totalTries >= 0;
+ }
+ }
+
+ for( testX = 0; testX < kGridAcross; testX++ )
+ {
+ for( testR = 0; testR < 4; testR++ )
+ {
+ testX2 = RandomBefore( kGridAcross );
+ testR2 = RandomBefore( 4 );
+
+ temp = shouldTry[testX][testR];
+ shouldTry[testX][testR] = shouldTry[testX2][testR2];
+ shouldTry[testX2][testR2] = temp;
+ }
+ }
+
+ shouldTry[0][leftRotate] = false;
+ shouldTry[kGridAcross-1][rightRotate] = false;
+
+ for( testX = 0; testX < kGridAcross; testX++ )
+ {
+ for( testR = 0; testR<=3; testR++ )
+ {
+ if( shouldTry[testX][testR] )
+ {
+ value = TestAIDestination( player, testX, testR );
+
+ if( value > bestValue )
+ {
+ bestValue = value;
+ currentBest = -1;
+ }
+
+ if( value == bestValue )
+ {
+ currentBest++;
+ bestX[currentBest] = testX;
+ bestR[currentBest] = testR;
+ }
+ }
+ }
+ }
+
+ currentBest = RandomBefore( currentBest + 1 );
+ destinationX[player] = bestX[currentBest];
+ destinationR[player] = bestR[currentBest];
+}
+
+int TestAIDestination( int player, int testX, int testR )
+{
+ int x, y, height, chains, rensa = 50, result = 0;
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ tempGrid[x][y] = grid[player][x][y];
+ }
+ }
+
+ height = GetRowHeight(player, testX);
+ switch( testR )
+ {
+ case upRotate:
+ tempGrid[testX][height--] = colorA[player];
+ if( height >= 0 ) tempGrid[testX][height] = colorB[player];
+ break;
+
+ case downRotate:
+ tempGrid[testX][height--] = colorB[player];
+ if( height >= 0 ) tempGrid[testX][height] = colorA[player];
+ break;
+
+ case leftRotate:
+ tempGrid[testX][height] = colorA[player];
+ tempGrid[testX-1][GetRowHeight(player,testX-1)] = colorB[player];
+ break;
+
+ case rightRotate:
+ tempGrid[testX][height] = colorA[player];
+ tempGrid[testX+1][GetRowHeight(player,testX+1)] = colorB[player];
+ break;
+ }
+
+ chains = TestTemporaryGrid( );
+
+ result = ScoreTemporaryGrid( );
+
+ if( (chains < 2) && (character[player].intellect > (24 * 2/3)) )
+ {
+ rensa = 0;
+ }
+ else
+ {
+ while( chains-- ) rensa *= 10;
+ }
+
+ result += rensa;
+
+ return result;
+}
+
+int ScoreTemporaryGrid( void )
+{
+ int x, y, change, result = 0;
+ int deductions[kGridAcross][kGridDown] =
+ { { 400, 350, 350, 200, 120, 60, 20, 5, 0, 0, 0, 0 },
+ { 600, 500, 300, 150, 100, 50, 20, 0, 0, 0, 0, 0 },
+ { 9999, 800, 200, 100, 50, 40, 20, 0, 0, 0, 0, 0 },
+ { 9999, 800, 200, 100, 50, 40, 20, 0, 0, 0, 0, 0 },
+ { 9999, 500, 300, 150, 100, 50, 20, 0, 0, 0, 0, 0 },
+ { 400, 350, 350, 200, 120, 60, 20, 5, 0, 0, 0, 0 } };
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ if( tempGrid[x][y] == kEmpty )
+ {
+ result += deductions[x][y];
+ }
+ else if( tempGrid[x][y] == kGray )
+ {
+ result -= deductions[x][y];
+ }
+ else
+ {
+ change = 0;
+
+ if( y < (kGridDown-1) && (tempGrid[x][y] == tempGrid[x][y+1]) ) change += 50;
+ if( y > 0 && (tempGrid[x][y] == tempGrid[x][y-1]) ) change += 50;
+ if( x < (kGridAcross-1) && (tempGrid[x][y] == tempGrid[x+1][y]) ) change += 40;
+ if( x > 0 && (tempGrid[x][y] == tempGrid[x-1][y]) ) change += 40;
+ if( x > 0 &&
+ y > 0 && (tempGrid[x][y] == tempGrid[x-1][y-1]) ) change += 20;
+ if( x < (kGridAcross-1) &&
+ y > 0 && (tempGrid[x][y] == tempGrid[x+1][y-1]) ) change += 20;
+ if( x > 0 &&
+ y < (kGridDown-1) && (tempGrid[x][y] == tempGrid[x-1][y+1]) ) change += 10;
+ if( x < (kGridAcross-1) &&
+ y < (kGridDown-1) && (tempGrid[x][y] == tempGrid[x+1][y+1]) ) change += 10;
+ if( y < (kGridDown-2) && (tempGrid[x][y] == tempGrid[x][y+2]) ) change += 10;
+ if( y > 1 && (tempGrid[x][y] == tempGrid[x][y-2]) ) change += 10;
+
+ if( (x > 0 && tempGrid[x-1][y] == kEmpty) ||
+ (x < (kGridAcross-1) && tempGrid[x+1][y] == kEmpty) ||
+ (y < 4 || tempGrid[x][y-4] == kEmpty) ) change *= 4;
+
+ result += change / 4;
+ }
+ }
+ }
+
+ return result;
+}
+
+int TestTemporaryGrid( void )
+{
+ MBoolean busy;
+ int x, y, stackSize, chains = 0;
+
+ do
+ {
+ busy = false;
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ if( tempGrid[x][y] >= kFirstBlob && tempGrid[x][y] <= kLastBlob )
+ {
+ if( SizeUp( tempGrid, x, y, tempGrid[x][y] ) >= kBlobClusterSize )
+ {
+ QuickRemove( tempGrid, x, y, tempGrid[x][y] );
+ busy = true;
+ }
+ }
+ }
+ }
+
+ if( busy )
+ {
+ chains++;
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ stackSize = kGridDown-1;
+
+ for( y=kGridDown-1; y>=0; y-- )
+ {
+ if( tempGrid[x][y] != kEmpty )
+ {
+ tempGrid[x][stackSize] = tempGrid[x][y];
+ if( y < stackSize ) tempGrid[x][y] = kEmpty;
+ stackSize--;
+ }
+ }
+ }
+ }
+ }
+ while( busy );
+
+ return chains;
+}
+
+void QuickRemove( signed char myGrid[kGridAcross][kGridDown], int x, int y, int color )
+{
+ if( (x<0) || (x>=kGridAcross) || (y<0) || (y>=kGridDown) )
+ return;
+
+ if( myGrid[x][y] == kGray ) myGrid[x][y] = kEmpty;
+ if( myGrid[x][y] == color )
+ {
+ myGrid[x][y] = kEmpty;
+ QuickRemove( myGrid, x-1, y, color );
+ QuickRemove( myGrid, x+1, y, color );
+ QuickRemove( myGrid, x, y-1, color );
+ QuickRemove( myGrid, x, y+1, color );
+ }
+}
+
+int BestColor( int player, int blobX, int blobY )
+{
+ int x, y, color, bestColor = kFirstBlob, bestResult = -9999999, rensa, chains, result;
+// char C[] = {' ', '*', '@', '.', '=', '+', 'o', 'J'};
+
+
+ for( color = kFirstBlob; color <= kLastBlob; color++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ for( x=0; x<kGridAcross; x++ )
+ {
+ tempGrid[x][y] = grid[player][x][y];
+ }
+ }
+
+ tempGrid[blobX][blobY] = color;
+
+ chains = TestTemporaryGrid( );
+ result = ScoreTemporaryGrid( );
+
+ rensa = 1000;
+ while( chains-- ) rensa *= 10;
+
+ result += rensa;
+
+ if( result > bestResult )
+ {
+ bestColor = color;
+ bestResult = result;
+ }
+ }
+
+ return bestColor;
+}
+
+// Returns the first empty row.
+int GetRowHeight( int player, int row )
+{
+ int height;
+
+ for( height = (kGridDown-1); height > 0; height-- )
+ {
+ if( grid[player][row][height] == kEmpty ) break;
+ }
+
+ return height;
+}
+
+int DetermineEmotion( int player )
+{
+ int us = 0, them = 0, aboveWater = 1;
+ int x,y;
+
+ if( role[player] == kLosing ) return kEmotionPanic;
+ if( role[player] == kWinning ) return kEmotionHappy;
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ if( aboveWater && (y<3) && (grid[player][x][y] != kEmpty) ) aboveWater = 0;
+ if( grid[player][x][y] != kEmpty ) us++;
+ if( grid[1-player][x][y] != kEmpty ) them++;
+ }
+ }
+
+ if( us > 48 && !aboveWater ) return kEmotionPanic;
+ else if( abs(us-them) < 12 ) return kEmotionNeutral;
+ else if( us > them ) return kEmotionSad;
+ else return kEmotionHappy;
+}
--- a/src/control.cpp
+++ /dev/null
@@ -1,629 +1,0 @@
-// control.c
-
-#include "main.h"
-#include "control.h"
-#include "moving.h"
-#include "players.h"
-#include "random.h"
-#include "grays.h"
-#include "zap.h"
-#include "gameticks.h"
-#include "level.h"
-#include "tutorial.h"
-#include <stdlib.h>
-
-int destinationX[2], destinationR[2];
-signed char tempGrid[kGridAcross][kGridDown];
-MTicks timeAI[2], timeMove[2];
-MBoolean moveQuick[2];
-AutoPatternPtr autoPattern = NULL;
-
-void AutoControl( int player )
-{
- if( autoPattern )
- {
- switch( autoPattern->command )
- {
- case kMessage:
- StartBalloon( autoPattern->message );
- autoPattern++;
- break;
-
- case kIdleTicks:
- if( !tutorialTime )
- {
- tutorialTime = GameTickCount() + autoPattern->d1;
- }
- else
- {
- if( GameTickCount() >= tutorialTime )
- {
- tutorialTime = 0;
- autoPattern++;
- }
- }
- break;
-
- case kRetrieve:
- if( role[player] == kWaitForRetrieval )
- {
- nextA[player] = abs( autoPattern->d1 );
- nextB[player] = abs( autoPattern->d2 );
- nextM[player] = (autoPattern->d1 < 0);
- nextG[player] = (autoPattern->d1 == kBombBottom) && (autoPattern->d2 == kBombTop);
-
- if( !nextG[player] )
- {
- nextA[player] = pieceMap[ nextA[player] ];
- nextB[player] = pieceMap[ nextB[player] ];
- }
-
- role[player] = kRetrieveBlobs;
- autoPattern++;
- }
- break;
-
- case kPosition:
- if( (role[player] != kFalling) || (blobX[player] == autoPattern->d1) )
- {
- autoPattern++;
- }
- else if( GameTickCount() >= timeMove[player] )
- {
- timeMove[player] = GameTickCount() + 12;
-
- if( blobX[player] > autoPattern->d1 )
- {
- if( CanGoLeft( player ) )
- GoLeft( player );
- }
- else
- {
- if( CanGoRight( player ) )
- GoRight( player );
- }
- }
- break;
-
- case kSpin:
- if( role[player] != kFalling )
- {
- autoPattern++;
- }
- else if( CanRotate( player ) )
- {
- DoRotate( player );
- autoPattern++;
- }
- break;
-
- case kBlockUntilLand:
- if( role[player] != kFalling )
- {
- autoPattern++;
- }
- break;
-
- case kBlockUntilDrop:
- if( !dropping[player] ) DoDrop( player );
-
- if( role[player] != kFalling )
- {
- autoPattern++;
- }
- break;
-
- case kPunish:
- if( role[player] == kWaitForRetrieval )
- {
- lockGrays[player] = autoPattern->d1;
- SetupGrays( player );
- blobTime[player] = GameTickCount( );
- role[player] = kDropGrays;
-
- autoPattern++;
- }
- break;
-
- case kComplete:
- EndTutorial( );
- break;
-
- case kBlockUntilComplete:
- if( role[player] == kWaitForRetrieval )
- {
- autoPattern++;
- }
- break;
- }
- }
-}
-
-void PlayerControl( int player )
-{
- int a = player, b = player;
- MBoolean moved = false;
-
- if( players == 1 )
- {
- a = 0;
- b = 1;
- }
-
- if( hitKey[a].left || hitKey[b].left )
- {
- if( GameTickCount() >= timeMove[player] )
- {
- timeMove[player] += 12;
- if( CanGoLeft( player ) )
- GoLeft( player );
- }
-
- moved = true;
- }
-
- if( hitKey[a].right || hitKey[b].right )
- {
- if( GameTickCount() >= timeMove[player] )
- {
- timeMove[player] += 12;
- if( CanGoRight( player ) )
- GoRight( player );
- }
-
- moved = true;
- }
-
- if( !moved ) timeMove[player] = GameTickCount( );
-
- if( hitKey[a].rotate == 1 || hitKey[b].rotate == 1 )
- {
- if( CanRotate( player ) )
- DoRotate( player );
- }
-
- if( hitKey[a].drop == 1 || hitKey[b].drop == 1 )
- {
- DoDrop( player );
- }
-
- if( hitKey[a].drop == 0 && hitKey[b].drop == 0 )
- {
- StopDrop( player );
- }
-}
-
-void AIControl( int player )
-{
- if( timeAI[player] > GameTickCount() )
- return;
-
- timeAI[player] += moveQuick[player]? character[player].speedRush:
- character[player].speedNormal;
-
- switch( RandomBefore( 2 ) )
- {
- case 0:
- if( destinationR[player] != blobR[player] )
- {
- if( CanRotate(player) )
- {
- DoRotate( player );
- }
- }
- break;
-
- case 1:
- if( destinationX[player] != blobX[player] )
- {
- if( destinationX[player] > blobX[player] )
- {
- if( CanGoRight( player ) )
- GoRight( player );
- }
- else
- {
- if( CanGoLeft( player ) )
- GoLeft( player );
- }
- }
- break;
- }
-
- if( destinationX[player] == blobX[player] &&
- destinationR[player] == blobR[player] &&
- RandomBefore( 100 ) < character[player].intellect )
- {
- DoDrop( player );
- }
-}
-
-void ChooseAIDestination( int player )
-{
- int testX, testR, testX2, testR2, value, bestValue = -9999999;
- int x, y;
- int bestX[kGridAcross*4], bestR[kGridAcross*4], currentBest = -1;
- int rowDifference, totalTries, temp;
- MBoolean shouldTry[kGridAcross][4];
-
- timeAI[player] = GameTickCount( ) + 1;
- moveQuick[player] = true;
-
- if( grenade[player] )
- {
- bestValue = 0;
- currentBest = 2;
-
- for( testX = 0; testX < kGridAcross; testX++ )
- {
- rowDifference = GetRowHeight( player, testX );
-
- if( (rowDifference < kGridDown - 1) &&
- (grid[player][testX][rowDifference+1] >= kFirstBlob) &&
- (grid[player][testX][rowDifference+1] <= kLastBlob) )
- {
- value = 0;
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- if( grid[player][x][y] == grid[player][testX][rowDifference+1] ) value++;
- }
- }
-
- if( value > bestValue )
- {
- bestValue = value;
- currentBest = testX;
- }
- }
- }
-
- destinationR[player] = upRotate;
- destinationX[player] = currentBest;
- return;
- }
-
- if( (GameTickCount() - startTime) <= 3600 )
- {
- for( testX = 0; testX < kGridAcross; testX++ )
- {
- rowDifference = GetRowHeight( player, testX ) - character[player].autoSetup[testX];
-
- if( rowDifference >= 2 )
- {
- destinationR[player] = downRotate;
- destinationX[player] = testX;
- return;
- }
-
- if( rowDifference == 1 )
- {
- destinationX[player] = testX;
-
- if( testX > 0 )
- {
- if( GetRowHeight( player, testX-1 ) > character[player].autoSetup[testX-1] )
- {
- destinationR[player] = leftRotate;
- return;
- }
- }
-
- if( testX < (kGridAcross-1) )
- {
- if( GetRowHeight( player, testX+1 ) > character[player].autoSetup[testX+1] )
- {
- destinationR[player] = rightRotate;
- return;
- }
- }
-
- destinationR[player] = upRotate;
- return;
- }
- }
- }
-
- moveQuick[player] = (emotions[player] == kEmotionSad) || (emotions[player] == kEmotionPanic);
-
- totalTries = character[player].intellect;
- for( testX = 0; testX < kGridAcross; testX++ )
- {
- for( testR = 0; testR < 4; testR++ )
- {
- shouldTry[testX][testR] = --totalTries >= 0;
- }
- }
-
- for( testX = 0; testX < kGridAcross; testX++ )
- {
- for( testR = 0; testR < 4; testR++ )
- {
- testX2 = RandomBefore( kGridAcross );
- testR2 = RandomBefore( 4 );
-
- temp = shouldTry[testX][testR];
- shouldTry[testX][testR] = shouldTry[testX2][testR2];
- shouldTry[testX2][testR2] = temp;
- }
- }
-
- shouldTry[0][leftRotate] = false;
- shouldTry[kGridAcross-1][rightRotate] = false;
-
- for( testX = 0; testX < kGridAcross; testX++ )
- {
- for( testR = 0; testR<=3; testR++ )
- {
- if( shouldTry[testX][testR] )
- {
- value = TestAIDestination( player, testX, testR );
-
- if( value > bestValue )
- {
- bestValue = value;
- currentBest = -1;
- }
-
- if( value == bestValue )
- {
- currentBest++;
- bestX[currentBest] = testX;
- bestR[currentBest] = testR;
- }
- }
- }
- }
-
- currentBest = RandomBefore( currentBest + 1 );
- destinationX[player] = bestX[currentBest];
- destinationR[player] = bestR[currentBest];
-}
-
-int TestAIDestination( int player, int testX, int testR )
-{
- int x, y, height, chains, rensa = 50, result = 0;
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- tempGrid[x][y] = grid[player][x][y];
- }
- }
-
- height = GetRowHeight(player, testX);
- switch( testR )
- {
- case upRotate:
- tempGrid[testX][height--] = colorA[player];
- if( height >= 0 ) tempGrid[testX][height] = colorB[player];
- break;
-
- case downRotate:
- tempGrid[testX][height--] = colorB[player];
- if( height >= 0 ) tempGrid[testX][height] = colorA[player];
- break;
-
- case leftRotate:
- tempGrid[testX][height] = colorA[player];
- tempGrid[testX-1][GetRowHeight(player,testX-1)] = colorB[player];
- break;
-
- case rightRotate:
- tempGrid[testX][height] = colorA[player];
- tempGrid[testX+1][GetRowHeight(player,testX+1)] = colorB[player];
- break;
- }
-
- chains = TestTemporaryGrid( );
-
- result = ScoreTemporaryGrid( );
-
- if( (chains < 2) && (character[player].intellect > (24 * 2/3)) )
- {
- rensa = 0;
- }
- else
- {
- while( chains-- ) rensa *= 10;
- }
-
- result += rensa;
-
- return result;
-}
-
-int ScoreTemporaryGrid( void )
-{
- int x, y, change, result = 0;
- int deductions[kGridAcross][kGridDown] =
- { { 400, 350, 350, 200, 120, 60, 20, 5, 0, 0, 0, 0 },
- { 600, 500, 300, 150, 100, 50, 20, 0, 0, 0, 0, 0 },
- { 9999, 800, 200, 100, 50, 40, 20, 0, 0, 0, 0, 0 },
- { 9999, 800, 200, 100, 50, 40, 20, 0, 0, 0, 0, 0 },
- { 9999, 500, 300, 150, 100, 50, 20, 0, 0, 0, 0, 0 },
- { 400, 350, 350, 200, 120, 60, 20, 5, 0, 0, 0, 0 } };
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- if( tempGrid[x][y] == kEmpty )
- {
- result += deductions[x][y];
- }
- else if( tempGrid[x][y] == kGray )
- {
- result -= deductions[x][y];
- }
- else
- {
- change = 0;
-
- if( y < (kGridDown-1) && (tempGrid[x][y] == tempGrid[x][y+1]) ) change += 50;
- if( y > 0 && (tempGrid[x][y] == tempGrid[x][y-1]) ) change += 50;
- if( x < (kGridAcross-1) && (tempGrid[x][y] == tempGrid[x+1][y]) ) change += 40;
- if( x > 0 && (tempGrid[x][y] == tempGrid[x-1][y]) ) change += 40;
- if( x > 0 &&
- y > 0 && (tempGrid[x][y] == tempGrid[x-1][y-1]) ) change += 20;
- if( x < (kGridAcross-1) &&
- y > 0 && (tempGrid[x][y] == tempGrid[x+1][y-1]) ) change += 20;
- if( x > 0 &&
- y < (kGridDown-1) && (tempGrid[x][y] == tempGrid[x-1][y+1]) ) change += 10;
- if( x < (kGridAcross-1) &&
- y < (kGridDown-1) && (tempGrid[x][y] == tempGrid[x+1][y+1]) ) change += 10;
- if( y < (kGridDown-2) && (tempGrid[x][y] == tempGrid[x][y+2]) ) change += 10;
- if( y > 1 && (tempGrid[x][y] == tempGrid[x][y-2]) ) change += 10;
-
- if( (x > 0 && tempGrid[x-1][y] == kEmpty) ||
- (x < (kGridAcross-1) && tempGrid[x+1][y] == kEmpty) ||
- (y < 4 || tempGrid[x][y-4] == kEmpty) ) change *= 4;
-
- result += change / 4;
- }
- }
- }
-
- return result;
-}
-
-int TestTemporaryGrid( void )
-{
- MBoolean busy;
- int x, y, stackSize, chains = 0;
-
- do
- {
- busy = false;
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- if( tempGrid[x][y] >= kFirstBlob && tempGrid[x][y] <= kLastBlob )
- {
- if( SizeUp( tempGrid, x, y, tempGrid[x][y] ) >= kBlobClusterSize )
- {
- QuickRemove( tempGrid, x, y, tempGrid[x][y] );
- busy = true;
- }
- }
- }
- }
-
- if( busy )
- {
- chains++;
-
- for( x=0; x<kGridAcross; x++ )
- {
- stackSize = kGridDown-1;
-
- for( y=kGridDown-1; y>=0; y-- )
- {
- if( tempGrid[x][y] != kEmpty )
- {
- tempGrid[x][stackSize] = tempGrid[x][y];
- if( y < stackSize ) tempGrid[x][y] = kEmpty;
- stackSize--;
- }
- }
- }
- }
- }
- while( busy );
-
- return chains;
-}
-
-void QuickRemove( signed char myGrid[kGridAcross][kGridDown], int x, int y, int color )
-{
- if( (x<0) || (x>=kGridAcross) || (y<0) || (y>=kGridDown) )
- return;
-
- if( myGrid[x][y] == kGray ) myGrid[x][y] = kEmpty;
- if( myGrid[x][y] == color )
- {
- myGrid[x][y] = kEmpty;
- QuickRemove( myGrid, x-1, y, color );
- QuickRemove( myGrid, x+1, y, color );
- QuickRemove( myGrid, x, y-1, color );
- QuickRemove( myGrid, x, y+1, color );
- }
-}
-
-int BestColor( int player, int blobX, int blobY )
-{
- int x, y, color, bestColor = kFirstBlob, bestResult = -9999999, rensa, chains, result;
-// char C[] = {' ', '*', '@', '.', '=', '+', 'o', 'J'};
-
-
- for( color = kFirstBlob; color <= kLastBlob; color++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- for( x=0; x<kGridAcross; x++ )
- {
- tempGrid[x][y] = grid[player][x][y];
- }
- }
-
- tempGrid[blobX][blobY] = color;
-
- chains = TestTemporaryGrid( );
- result = ScoreTemporaryGrid( );
-
- rensa = 1000;
- while( chains-- ) rensa *= 10;
-
- result += rensa;
-
- if( result > bestResult )
- {
- bestColor = color;
- bestResult = result;
- }
- }
-
- return bestColor;
-}
-
-// Returns the first empty row.
-int GetRowHeight( int player, int row )
-{
- int height;
-
- for( height = (kGridDown-1); height > 0; height-- )
- {
- if( grid[player][row][height] == kEmpty ) break;
- }
-
- return height;
-}
-
-int DetermineEmotion( int player )
-{
- int us = 0, them = 0, aboveWater = 1;
- int x,y;
-
- if( role[player] == kLosing ) return kEmotionPanic;
- if( role[player] == kWinning ) return kEmotionHappy;
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- if( aboveWater && (y<3) && (grid[player][x][y] != kEmpty) ) aboveWater = 0;
- if( grid[player][x][y] != kEmpty ) us++;
- if( grid[1-player][x][y] != kEmpty ) them++;
- }
- }
-
- if( us > 48 && !aboveWater ) return kEmotionPanic;
- else if( abs(us-them) < 12 ) return kEmotionNeutral;
- else if( us > them ) return kEmotionSad;
- else return kEmotionHappy;
-}
--- /dev/null
+++ b/src/font.c
@@ -1,0 +1,119 @@
+// font.c
+
+#include "SDLU.h"
+
+#include "main.h"
+#include "font.h"
+#include "gworld.h"
+
+
+#define kNumFonts (picBatsuFont-picFont+1)
+
+static SkittlesFont s_font[kNumFonts];
+
+
+static SkittlesFontPtr LoadFont( SkittlesFontPtr font, int pictID, unsigned char *letterMap )
+{
+ unsigned char* lastLine;
+ unsigned char white;
+ MBoolean success = false;
+ int start, across, skip;
+ SDL_Surface* temporarySurface;
+ SDL_Rect sdlRect;
+
+ temporarySurface = LoadPICTAsSurface( pictID, 8 );
+
+ if( temporarySurface )
+ {
+ sdlRect.x = 0;
+ sdlRect.y = 0;
+ sdlRect.h = temporarySurface->h;
+ sdlRect.w = temporarySurface->w;
+
+ font->surface = SDLU_InitSurface( &sdlRect, 8 );
+
+ SDLU_BlitSurface( temporarySurface, &temporarySurface->clip_rect,
+ font->surface, &temporarySurface->clip_rect );
+
+ SDL_FreeSurface( temporarySurface );
+
+ white = SDL_MapRGB( font->surface->format, 0xFF, 0xFF, 0xFF );
+ lastLine = (unsigned char*) font->surface->pixels + (font->surface->pitch * (font->surface->h - 1));
+ across = 0;
+
+ // Measure empty space between character breaks
+ while( lastLine[across] == white ) across++;
+ skip = across;
+
+ success = true;
+
+ // Measure character starts and widths
+ while( *letterMap )
+ {
+ while( lastLine[across] != white ) across++;
+ if( across > font->surface->pitch )
+ {
+ success = false;
+ break;
+ }
+
+ start = across;
+ font->across[*letterMap] = across + (skip/2);
+
+ while( lastLine[across] == white ) across++;
+ font->width [*letterMap] = across - start - skip;
+
+ letterMap++;
+ }
+ }
+
+ if( success )
+ {
+ return font;
+ }
+ else
+ {
+ Error( "LoadFont: files are missing or corrupt" );
+ return NULL;
+ }
+}
+
+
+void InitFont( void )
+{
+ LoadFont( &s_font[0], picFont, (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!:,.()*?0123456789'|-\x01\x02\x03\x04\x05 " );
+ LoadFont( &s_font[1], picHiScoreFont, (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*().,/-=_+<>?|'\":; " );
+ LoadFont( &s_font[2], picContinueFont, (unsigned char*) "0123456789" );
+ LoadFont( &s_font[3], picBalloonFont, (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-=_+;:,./<>? \x01\x02'\"" );
+ LoadFont( &s_font[4], picZapFont, (unsigned char*) "0123456789*PS" );
+ LoadFont( &s_font[5], picZapOutlineFont, (unsigned char*) "0123456789*" );
+ LoadFont( &s_font[6], picVictoryFont, (unsigned char*) "AB" );
+ LoadFont( &s_font[7], picBubbleFont, (unsigned char*) "*" );
+ LoadFont( &s_font[8], picTinyFont, (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,.!`-=[];'/~_+{}:\"\\ " );
+ LoadFont( &s_font[9], picDashedLineFont, (unsigned char*) "." );
+ LoadFont( &s_font[10], picBatsuFont, (unsigned char*) "X" );
+}
+
+
+SkittlesFontPtr GetFont( int pictID )
+{
+ int fontID = pictID - picFont;
+
+ if( (fontID < 0) || (fontID >= kNumFonts) )
+ Error( "GetFont: fontID" );
+
+ return &s_font[fontID];
+}
+
+
+int GetTextWidth( SkittlesFontPtr font, const char *text )
+{
+ int width = 0;
+ while( *text )
+ {
+ width += font->width[(uint8_t) *text++];
+ }
+
+ return width;
+}
+
--- a/src/font.cpp
+++ /dev/null
@@ -1,119 +1,0 @@
-// font.c
-
-#include "SDLU.h"
-
-#include "main.h"
-#include "font.h"
-#include "gworld.h"
-
-
-const int kNumFonts = (picBatsuFont-picFont+1);
-
-static SkittlesFont s_font[kNumFonts] = {};
-
-
-static SkittlesFontPtr LoadFont( SkittlesFontPtr font, int pictID, unsigned char *letterMap )
-{
- unsigned char* lastLine;
- unsigned char white;
- MBoolean success = false;
- int start, across, skip;
- SDL_Surface* temporarySurface;
- SDL_Rect sdlRect;
-
- temporarySurface = LoadPICTAsSurface( pictID, 8 );
-
- if( temporarySurface )
- {
- sdlRect.x = 0;
- sdlRect.y = 0;
- sdlRect.h = temporarySurface->h;
- sdlRect.w = temporarySurface->w;
-
- font->surface = SDLU_InitSurface( &sdlRect, 8 );
-
- SDLU_BlitSurface( temporarySurface, &temporarySurface->clip_rect,
- font->surface, &temporarySurface->clip_rect );
-
- SDL_FreeSurface( temporarySurface );
-
- white = SDL_MapRGB( font->surface->format, 0xFF, 0xFF, 0xFF );
- lastLine = (unsigned char*) font->surface->pixels + (font->surface->pitch * (font->surface->h - 1));
- across = 0;
-
- // Measure empty space between character breaks
- while( lastLine[across] == white ) across++;
- skip = across;
-
- success = true;
-
- // Measure character starts and widths
- while( *letterMap )
- {
- while( lastLine[across] != white ) across++;
- if( across > font->surface->pitch )
- {
- success = false;
- break;
- }
-
- start = across;
- font->across[*letterMap] = across + (skip/2);
-
- while( lastLine[across] == white ) across++;
- font->width [*letterMap] = across - start - skip;
-
- letterMap++;
- }
- }
-
- if( success )
- {
- return font;
- }
- else
- {
- Error( "LoadFont: files are missing or corrupt" );
- return NULL;
- }
-}
-
-
-void InitFont( void )
-{
- LoadFont( &s_font[0], picFont, (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!:,.()*?0123456789'|-\x01\x02\x03\x04\x05 " );
- LoadFont( &s_font[1], picHiScoreFont, (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*().,/-=_+<>?|'\":; " );
- LoadFont( &s_font[2], picContinueFont, (unsigned char*) "0123456789" );
- LoadFont( &s_font[3], picBalloonFont, (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-=_+;:,./<>? \x01\x02'\"" );
- LoadFont( &s_font[4], picZapFont, (unsigned char*) "0123456789*PS" );
- LoadFont( &s_font[5], picZapOutlineFont, (unsigned char*) "0123456789*" );
- LoadFont( &s_font[6], picVictoryFont, (unsigned char*) "AB" );
- LoadFont( &s_font[7], picBubbleFont, (unsigned char*) "*" );
- LoadFont( &s_font[8], picTinyFont, (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,.!`-=[];'/~_+{}:\"\\ " );
- LoadFont( &s_font[9], picDashedLineFont, (unsigned char*) "." );
- LoadFont( &s_font[10], picBatsuFont, (unsigned char*) "X" );
-}
-
-
-SkittlesFontPtr GetFont( int pictID )
-{
- int fontID = pictID - picFont;
-
- if( (fontID < 0) || (fontID >= kNumFonts) )
- Error( "GetFont: fontID" );
-
- return &s_font[fontID];
-}
-
-
-int GetTextWidth( SkittlesFontPtr font, const char *text )
-{
- int width = 0;
- while( *text )
- {
- width += font->width[(uint8_t) *text++];
- }
-
- return width;
-}
-
--- /dev/null
+++ b/src/gameticks.c
@@ -1,0 +1,45 @@
+// gameticks.c
+
+#include <SDL_timer.h>
+#include "gameticks.h"
+
+MTicks baseTickCount, freezeTickCount;
+int freezeLevel;
+
+MTicks MTickCount()
+{
+ return (unsigned int ) ((float)SDL_GetTicks() * 0.06f);
+}
+
+void InitGameTickCount( void )
+{
+ baseTickCount = freezeTickCount = 0;
+ freezeLevel = 0;
+}
+
+void FreezeGameTickCount( void )
+{
+ if( freezeLevel == 0 )
+ {
+ freezeTickCount = MTickCount( );
+ }
+ freezeLevel--;
+}
+
+void UnfreezeGameTickCount( void )
+{
+ freezeLevel++;
+ if( freezeLevel >= 0 )
+ {
+ freezeLevel = 0;
+ baseTickCount += MTickCount( ) - freezeTickCount;
+ }
+}
+
+unsigned int GameTickCount( void )
+{
+ if( freezeLevel < 0 )
+ return freezeTickCount - baseTickCount;
+
+ return MTickCount( ) - baseTickCount;
+}
--- a/src/gameticks.cpp
+++ /dev/null
@@ -1,45 +1,0 @@
-// gameticks.c
-
-#include <SDL_timer.h>
-#include "gameticks.h"
-
-MTicks baseTickCount, freezeTickCount;
-int freezeLevel;
-
-MTicks MTickCount()
-{
- return (unsigned int ) ((float)SDL_GetTicks() * 0.06f);
-}
-
-void InitGameTickCount( void )
-{
- baseTickCount = freezeTickCount = 0;
- freezeLevel = 0;
-}
-
-void FreezeGameTickCount( void )
-{
- if( freezeLevel == 0 )
- {
- freezeTickCount = MTickCount( );
- }
- freezeLevel--;
-}
-
-void UnfreezeGameTickCount( void )
-{
- freezeLevel++;
- if( freezeLevel >= 0 )
- {
- freezeLevel = 0;
- baseTickCount += MTickCount( ) - freezeTickCount;
- }
-}
-
-unsigned int GameTickCount( void )
-{
- if( freezeLevel < 0 )
- return freezeTickCount - baseTickCount;
-
- return MTickCount( ) - baseTickCount;
-}
--- /dev/null
+++ b/src/graphics.c
@@ -1,0 +1,199 @@
+// graphics.c
+
+#include <stdlib.h>
+#include "version.h"
+#include "SDLU.h"
+#include "main.h"
+#include "players.h"
+#include "graphics.h"
+#include "gworld.h"
+#include "moving.h"
+#include "tweak.h"
+#include "gameticks.h"
+#include "blitter.h"
+#include "victory.h"
+#include "grays.h"
+#include "level.h"
+#include "keyselect.h"
+
+
+SDL_Surface* backdropSurface = NULL;
+
+
+void DrawSpriteBlobs( int player, int type )
+{
+ MRect firstRect, secondRect, thirdRect;
+
+#define repeat 0xFF
+#define forever 0xFE
+
+ static const unsigned char blobAnimation[6][2][25] =
+ {
+ { { kNoSuction, kNoSuction, kNoSuction, kNoSuction,
+ kNoSuction, kNoSuction, kNoSuction, kNoSuction,
+ kNoSuction, kNoSuction, kNoSuction, kNoSuction,
+ kFlashBrightBlob, kFlashBrightBlob, kFlashBrightBlob, kFlashBrightBlob,
+ kFlashBrightBlob, kFlashBrightBlob, kFlashBrightBlob, kFlashBrightBlob,
+ kFlashBrightBlob, kFlashBrightBlob, kFlashBrightBlob, kFlashBrightBlob, repeat },
+ { kNoSuction, kNoSuction, kNoSuction, kNoSuction,
+ kNoSuction, kNoSuction, kNoSuction, kNoSuction,
+ kNoSuction, kNoSuction, kNoSuction, kNoSuction,
+ kNoSuction, kNoSuction, kNoSuction, kNoSuction,
+ kNoSuction, kNoSuction, kNoSuction, kNoSuction,
+ kNoSuction, kNoSuction, kNoSuction, kNoSuction, repeat } },
+ { { kNoSuction, kSquish, kNoSuction, kSquash,
+ kNoSuction, kSquish, kNoSuction, kSquash,
+ kNoSuction, forever },
+ { kNoSuction, kSquish, kNoSuction, kSquash,
+ kNoSuction, kSquish, kNoSuction, kSquash,
+ kNoSuction, forever } },
+ { { kSobBlob, kSobBlob, kSobBlob, kSobBlob,
+ kSob2Blob, kSob2Blob, kSob2Blob, kSob2Blob,
+ repeat },
+ { kSobBlob, kSobBlob, kSobBlob, kSobBlob,
+ kSob2Blob, kSob2Blob, kSob2Blob, kSob2Blob,
+ repeat } },
+ { { kBombFuse1, kBombFuse2, kBombFuse3, repeat },
+ { kBombFuse1, kBombFuse2, kBombFuse3, repeat } },
+ { { kBlinkBomb1, kBombFuse2, kBlinkBomb3, kBombFuse1,
+ kBlinkBomb2, kBombFuse3, repeat },
+ { kBlinkBomb1, kBombFuse2, kBlinkBomb3, kBombFuse1,
+ kBlinkBomb2, kBombFuse3, repeat } }
+ };
+
+ if( grenade[player] ) type += 3;
+
+ SDLU_AcquireSurface( playerSpriteSurface[player] );
+
+ if( blobAnimation[type][0][anim[player]] == forever ) anim[player]--;
+ if( blobAnimation[type][0][anim[player]] == repeat ) anim[player] = 0;
+
+ CalcBlobRect( blobX[player], blobY[player], &firstRect );
+ if( halfway[player] ) OffsetMRect( &firstRect, 0, kBlobVertSize / 2 );
+
+ TweakFirstBlob ( player, &firstRect );
+ secondRect = firstRect;
+ TweakSecondBlob( player, &secondRect );
+
+ thirdRect = firstRect;
+ thirdRect.top -= kBlobShadowError;
+ thirdRect.left -= kBlobShadowError;
+ thirdRect.right += kBlobShadowDepth + kBlobShadowError;
+ thirdRect.bottom += kBlobShadowDepth + kBlobShadowError;
+ CleanSpriteArea( player, &thirdRect );
+
+ thirdRect = secondRect;
+ thirdRect.top -= kBlobShadowError;
+ thirdRect.left -= kBlobShadowError;
+ thirdRect.right += kBlobShadowDepth + kBlobShadowError;
+ thirdRect.bottom += kBlobShadowDepth + kBlobShadowError;
+ CleanSpriteArea( player, &thirdRect );
+
+ thirdRect = firstRect;
+ OffsetMRect( &thirdRect, shadowDepth[player], shadowDepth[player] );
+ SurfaceDrawShadow( &thirdRect, colorA[player], blobAnimation[type][0][anim[player]] );
+
+ thirdRect = secondRect;
+ OffsetMRect( &thirdRect, shadowDepth[player], shadowDepth[player] );
+ SurfaceDrawShadow( &thirdRect, colorB[player], blobAnimation[type][1][anim[player]] );
+
+ SurfaceDrawSprite( &firstRect, colorA[player], blobAnimation[type][0][anim[player]] );
+
+ SurfaceDrawSprite( &secondRect, colorB[player], blobAnimation[type][1][anim[player]] );
+
+ SDLU_ReleaseSurface( playerSpriteSurface[player] );
+
+#undef repeat
+#undef forever
+}
+
+void CleanSpriteArea( int player, MRect *myRect )
+{
+ SDL_Rect sdlRect;
+
+ SDLU_MRectToSDLRect( myRect, &sdlRect );
+
+ SDLU_BlitSurface( playerSurface[player], &sdlRect,
+ playerSpriteSurface[player], &sdlRect );
+
+ SetUpdateRect( player, myRect );
+}
+
+void EraseSpriteBlobs( int player )
+{
+ MRect myRect, secondRect;
+
+ CalcBlobRect( blobX[player], blobY[player], &myRect );
+ if( halfway[player] ) OffsetMRect( &myRect, 0, kBlobVertSize / 2 );
+
+ TweakFirstBlob( player, &myRect );
+ secondRect = myRect;
+ secondRect.top -= kBlobShadowError;
+ secondRect.left -= kBlobShadowError;
+ secondRect.right += kBlobShadowDepth + kBlobShadowError;
+ secondRect.bottom += kBlobShadowDepth + kBlobShadowError;
+ CleanSpriteArea( player, &secondRect );
+
+ TweakSecondBlob( player, &myRect );
+ myRect.top -= kBlobShadowError;
+ myRect.left -= kBlobShadowError;
+ myRect.right += kBlobShadowDepth + kBlobShadowError;
+ myRect.bottom += kBlobShadowDepth + kBlobShadowError;
+ CleanSpriteArea( player, &myRect );
+}
+
+void CalcBlobRect( int x, int y, MRect *myRect )
+{
+ myRect->top = y * kBlobVertSize;
+ myRect->left = x * kBlobHorizSize;
+ myRect->bottom = myRect->top + kBlobVertSize;
+ myRect->right = myRect->left + kBlobHorizSize;
+}
+
+void InitBackdrop( void )
+{
+ backdropSurface = LoadPICTAsSurface( picBackdrop, 32 );
+}
+
+void DrawBackdrop( void )
+{
+ SDL_Rect backdropRect = { 0, 0, 640, 480 };
+
+ SDLU_BlitFrontSurface( backdropSurface, &backdropRect, &backdropRect );
+}
+
+void ShowTitle( void )
+{
+ SDL_FillRect( g_frontSurface, &g_frontSurface->clip_rect, SDL_MapRGB( g_frontSurface->format, 0, 0, 0 ) );
+ SDLU_Present();
+
+ RetrieveResources( );
+
+ MTicks time = MTickCount() + 120;
+ SDLU_AcquireSurface( g_frontSurface );
+ DrawPICTInSurface( g_frontSurface, picTitle );
+
+ SkittlesFontPtr font = GetFont(picTinyFont);
+ MPoint dPoint;
+ dPoint.v = (widescreen ? 420 : 480) - 16;
+ dPoint.h = 4;
+ for (const char* scan = "Source port v" PROJECT_VERSION; *scan; scan++)
+ {
+ SurfaceBlitCharacter(font, *scan, &dPoint, 50, 50, 50, 1);
+ }
+ SDLU_ReleaseSurface( g_frontSurface );
+
+ while( time > MTickCount() && !SDLU_Button() )
+ {
+ SDLU_Present();
+ SDLU_Yield();
+ }
+
+ WaitForRelease();
+
+ QuickFadeOut( NULL );
+
+ SDL_FillRect( g_frontSurface, &g_frontSurface->clip_rect, SDL_MapRGB( g_frontSurface->format, 0, 0, 0 ) );
+ SDLU_Present();
+}
+
--- a/src/graphics.cpp
+++ /dev/null
@@ -1,194 +1,0 @@
-// graphics.c
-
-#include <stdlib.h>
-#include "version.h"
-#include "SDLU.h"
-#include "main.h"
-#include "players.h"
-#include "graphics.h"
-#include "gworld.h"
-#include "moving.h"
-#include "tweak.h"
-#include "gameticks.h"
-#include "blitter.h"
-#include "victory.h"
-#include "grays.h"
-#include "level.h"
-#include "keyselect.h"
-
-
-SDL_Surface* backdropSurface = NULL;
-
-
-void DrawSpriteBlobs( int player, int type )
-{
- MRect firstRect, secondRect, thirdRect;
- const int repeat = 0xFF, forever = 0xFE;
-
- static const unsigned char blobAnimation[6][2][25] =
- {
- { { kNoSuction, kNoSuction, kNoSuction, kNoSuction,
- kNoSuction, kNoSuction, kNoSuction, kNoSuction,
- kNoSuction, kNoSuction, kNoSuction, kNoSuction,
- kFlashBrightBlob, kFlashBrightBlob, kFlashBrightBlob, kFlashBrightBlob,
- kFlashBrightBlob, kFlashBrightBlob, kFlashBrightBlob, kFlashBrightBlob,
- kFlashBrightBlob, kFlashBrightBlob, kFlashBrightBlob, kFlashBrightBlob, repeat },
- { kNoSuction, kNoSuction, kNoSuction, kNoSuction,
- kNoSuction, kNoSuction, kNoSuction, kNoSuction,
- kNoSuction, kNoSuction, kNoSuction, kNoSuction,
- kNoSuction, kNoSuction, kNoSuction, kNoSuction,
- kNoSuction, kNoSuction, kNoSuction, kNoSuction,
- kNoSuction, kNoSuction, kNoSuction, kNoSuction, repeat } },
- { { kNoSuction, kSquish, kNoSuction, kSquash,
- kNoSuction, kSquish, kNoSuction, kSquash,
- kNoSuction, forever },
- { kNoSuction, kSquish, kNoSuction, kSquash,
- kNoSuction, kSquish, kNoSuction, kSquash,
- kNoSuction, forever } },
- { { kSobBlob, kSobBlob, kSobBlob, kSobBlob,
- kSob2Blob, kSob2Blob, kSob2Blob, kSob2Blob,
- repeat },
- { kSobBlob, kSobBlob, kSobBlob, kSobBlob,
- kSob2Blob, kSob2Blob, kSob2Blob, kSob2Blob,
- repeat } },
- { { kBombFuse1, kBombFuse2, kBombFuse3, repeat },
- { kBombFuse1, kBombFuse2, kBombFuse3, repeat } },
- { { kBlinkBomb1, kBombFuse2, kBlinkBomb3, kBombFuse1,
- kBlinkBomb2, kBombFuse3, repeat },
- { kBlinkBomb1, kBombFuse2, kBlinkBomb3, kBombFuse1,
- kBlinkBomb2, kBombFuse3, repeat } }
- };
-
- if( grenade[player] ) type += 3;
-
- SDLU_AcquireSurface( playerSpriteSurface[player] );
-
- if( blobAnimation[type][0][anim[player]] == forever ) anim[player]--;
- if( blobAnimation[type][0][anim[player]] == repeat ) anim[player] = 0;
-
- CalcBlobRect( blobX[player], blobY[player], &firstRect );
- if( halfway[player] ) OffsetMRect( &firstRect, 0, kBlobVertSize / 2 );
-
- TweakFirstBlob ( player, &firstRect );
- secondRect = firstRect;
- TweakSecondBlob( player, &secondRect );
-
- thirdRect = firstRect;
- thirdRect.top -= kBlobShadowError;
- thirdRect.left -= kBlobShadowError;
- thirdRect.right += kBlobShadowDepth + kBlobShadowError;
- thirdRect.bottom += kBlobShadowDepth + kBlobShadowError;
- CleanSpriteArea( player, &thirdRect );
-
- thirdRect = secondRect;
- thirdRect.top -= kBlobShadowError;
- thirdRect.left -= kBlobShadowError;
- thirdRect.right += kBlobShadowDepth + kBlobShadowError;
- thirdRect.bottom += kBlobShadowDepth + kBlobShadowError;
- CleanSpriteArea( player, &thirdRect );
-
- thirdRect = firstRect;
- OffsetMRect( &thirdRect, shadowDepth[player], shadowDepth[player] );
- SurfaceDrawShadow( &thirdRect, colorA[player], blobAnimation[type][0][anim[player]] );
-
- thirdRect = secondRect;
- OffsetMRect( &thirdRect, shadowDepth[player], shadowDepth[player] );
- SurfaceDrawShadow( &thirdRect, colorB[player], blobAnimation[type][1][anim[player]] );
-
- SurfaceDrawSprite( &firstRect, colorA[player], blobAnimation[type][0][anim[player]] );
-
- SurfaceDrawSprite( &secondRect, colorB[player], blobAnimation[type][1][anim[player]] );
-
- SDLU_ReleaseSurface( playerSpriteSurface[player] );
-}
-
-void CleanSpriteArea( int player, MRect *myRect )
-{
- SDL_Rect sdlRect;
-
- SDLU_MRectToSDLRect( myRect, &sdlRect );
-
- SDLU_BlitSurface( playerSurface[player], &sdlRect,
- playerSpriteSurface[player], &sdlRect );
-
- SetUpdateRect( player, myRect );
-}
-
-void EraseSpriteBlobs( int player )
-{
- MRect myRect, secondRect;
-
- CalcBlobRect( blobX[player], blobY[player], &myRect );
- if( halfway[player] ) OffsetMRect( &myRect, 0, kBlobVertSize / 2 );
-
- TweakFirstBlob( player, &myRect );
- secondRect = myRect;
- secondRect.top -= kBlobShadowError;
- secondRect.left -= kBlobShadowError;
- secondRect.right += kBlobShadowDepth + kBlobShadowError;
- secondRect.bottom += kBlobShadowDepth + kBlobShadowError;
- CleanSpriteArea( player, &secondRect );
-
- TweakSecondBlob( player, &myRect );
- myRect.top -= kBlobShadowError;
- myRect.left -= kBlobShadowError;
- myRect.right += kBlobShadowDepth + kBlobShadowError;
- myRect.bottom += kBlobShadowDepth + kBlobShadowError;
- CleanSpriteArea( player, &myRect );
-}
-
-void CalcBlobRect( int x, int y, MRect *myRect )
-{
- myRect->top = y * kBlobVertSize;
- myRect->left = x * kBlobHorizSize;
- myRect->bottom = myRect->top + kBlobVertSize;
- myRect->right = myRect->left + kBlobHorizSize;
-}
-
-void InitBackdrop( void )
-{
- backdropSurface = LoadPICTAsSurface( picBackdrop, 32 );
-}
-
-void DrawBackdrop( void )
-{
- SDL_Rect backdropRect = { 0, 0, 640, 480 };
-
- SDLU_BlitFrontSurface( backdropSurface, &backdropRect, &backdropRect );
-}
-
-void ShowTitle( void )
-{
- SDL_FillRect( g_frontSurface, &g_frontSurface->clip_rect, SDL_MapRGB( g_frontSurface->format, 0, 0, 0 ) );
- SDLU_Present();
-
- RetrieveResources( );
-
- MTicks time = MTickCount() + 120;
- SDLU_AcquireSurface( g_frontSurface );
- DrawPICTInSurface( g_frontSurface, picTitle );
-
- SkittlesFontPtr font = GetFont(picTinyFont);
- MPoint dPoint;
- dPoint.v = (widescreen ? 420 : 480) - 16;
- dPoint.h = 4;
- for (const char* scan = "Source port v" PROJECT_VERSION; *scan; scan++)
- {
- SurfaceBlitCharacter(font, *scan, &dPoint, 50, 50, 50, 1);
- }
- SDLU_ReleaseSurface( g_frontSurface );
-
- while( time > MTickCount() && !SDLU_Button() )
- {
- SDLU_Present();
- SDLU_Yield();
- }
-
- WaitForRelease();
-
- QuickFadeOut( NULL );
-
- SDL_FillRect( g_frontSurface, &g_frontSurface->clip_rect, SDL_MapRGB( g_frontSurface->format, 0, 0, 0 ) );
- SDLU_Present();
-}
-
--- /dev/null
+++ b/src/graymonitor.c
@@ -1,0 +1,90 @@
+// graymonitor.c
+
+#include "SDLU.h"
+
+#include "main.h"
+#include "graymonitor.h"
+#include "grays.h"
+#include "score.h"
+#include "gworld.h"
+#include "graphics.h"
+#include "level.h"
+
+
+static SDL_Surface* smallGrayDrawSurface;
+
+
+MRect grayMonitorZRect, grayMonitorRect[2];
+MBoolean grayMonitorVisible[2] = {true, true};
+
+void InitGrayMonitors( void )
+{
+ const double windowLoc[ ] = { 0.16, 0.84 };
+ SDL_Rect sdlRect;
+
+ grayMonitorZRect.top = grayMonitorZRect.left = 0;
+ grayMonitorZRect.bottom = 32; grayMonitorZRect.right = 144;
+
+ grayMonitorRect[0] = grayMonitorRect[1] = grayMonitorZRect;
+ CenterRectOnScreen( &grayMonitorRect[0], windowLoc[0], 0.11 );
+ CenterRectOnScreen( &grayMonitorRect[1], windowLoc[1], 0.11 );
+
+ smallGrayDrawSurface = SDLU_InitSurface( SDLU_MRectToSDLRect( &grayMonitorZRect, &sdlRect ), 32 );
+ DrawPICTInSurface( smallGrayDrawSurface, picBoard );
+}
+
+void ShowGrayMonitor( short player )
+{
+ SDL_Rect sourceSDLRect, destSDLRect;
+ short monitor;
+ MRect myRect = { 4, 4, kBlobVertSize+4, 4 };
+ MRect srcRect;
+ const int smallGrayList[] = { 0, kSmallGray1, kSmallGray2, kSmallGray3, kSmallGray4, kSmallGray5 };
+
+ if( !grayMonitorVisible[player] ) return;
+
+ if( control[player] != kNobodyControl )
+ {
+ SDLU_AcquireSurface( smallGrayDrawSurface );
+
+ SDLU_BlitSurface( boardSurface[player], &smallGrayDrawSurface->clip_rect,
+ smallGrayDrawSurface, &smallGrayDrawSurface->clip_rect );
+
+ monitor = unallocatedGrays[player];
+
+ CalcBlobRect( kSobBlob, 3, &srcRect );
+ while( monitor >= (6*4) )
+ {
+ myRect.right += kBlobHorizSize;
+ SurfaceDrawSprite( &myRect, 4, kSobBlob );
+ myRect.left = myRect.right;
+
+ monitor -= (6*4);
+ }
+
+ CalcBlobRect( kNoSuction, kGray-1, &srcRect );
+ while( monitor >= 6 )
+ {
+ myRect.right += kBlobHorizSize;
+ SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
+ myRect.left = myRect.right;
+
+ monitor -= 6;
+ }
+
+ if( monitor > 0 )
+ {
+ myRect.right += kBlobHorizSize;
+ SurfaceDrawAlpha( &myRect, kGray, kLight, smallGrayList[monitor] );
+ myRect.left = myRect.right;
+ myRect.right += kBlobHorizSize;
+ SurfaceDrawAlpha( &myRect, kGray, kLight, smallGrayList[monitor]+1 );
+ }
+
+ SDLU_ReleaseSurface( smallGrayDrawSurface );
+
+ SDLU_BlitFrontSurface( smallGrayDrawSurface,
+ SDLU_MRectToSDLRect( &grayMonitorZRect, &sourceSDLRect ),
+ SDLU_MRectToSDLRect( &grayMonitorRect[player], &destSDLRect ) );
+ }
+}
--- a/src/graymonitor.cpp
+++ /dev/null
@@ -1,90 +1,0 @@
-// graymonitor.c
-
-#include "SDLU.h"
-
-#include "main.h"
-#include "graymonitor.h"
-#include "grays.h"
-#include "score.h"
-#include "gworld.h"
-#include "graphics.h"
-#include "level.h"
-
-
-static SDL_Surface* smallGrayDrawSurface;
-
-
-MRect grayMonitorZRect, grayMonitorRect[2];
-MBoolean grayMonitorVisible[2] = {true, true};
-
-void InitGrayMonitors( void )
-{
- const double windowLoc[ ] = { 0.16, 0.84 };
- SDL_Rect sdlRect;
-
- grayMonitorZRect.top = grayMonitorZRect.left = 0;
- grayMonitorZRect.bottom = 32; grayMonitorZRect.right = 144;
-
- grayMonitorRect[0] = grayMonitorRect[1] = grayMonitorZRect;
- CenterRectOnScreen( &grayMonitorRect[0], windowLoc[0], 0.11 );
- CenterRectOnScreen( &grayMonitorRect[1], windowLoc[1], 0.11 );
-
- smallGrayDrawSurface = SDLU_InitSurface( SDLU_MRectToSDLRect( &grayMonitorZRect, &sdlRect ), 32 );
- DrawPICTInSurface( smallGrayDrawSurface, picBoard );
-}
-
-void ShowGrayMonitor( short player )
-{
- SDL_Rect sourceSDLRect, destSDLRect;
- short monitor;
- MRect myRect = { 4, 4, kBlobVertSize+4, 4 };
- MRect srcRect;
- const int smallGrayList[] = { 0, kSmallGray1, kSmallGray2, kSmallGray3, kSmallGray4, kSmallGray5 };
-
- if( !grayMonitorVisible[player] ) return;
-
- if( control[player] != kNobodyControl )
- {
- SDLU_AcquireSurface( smallGrayDrawSurface );
-
- SDLU_BlitSurface( boardSurface[player], &smallGrayDrawSurface->clip_rect,
- smallGrayDrawSurface, &smallGrayDrawSurface->clip_rect );
-
- monitor = unallocatedGrays[player];
-
- CalcBlobRect( kSobBlob, 3, &srcRect );
- while( monitor >= (6*4) )
- {
- myRect.right += kBlobHorizSize;
- SurfaceDrawSprite( &myRect, 4, kSobBlob );
- myRect.left = myRect.right;
-
- monitor -= (6*4);
- }
-
- CalcBlobRect( kNoSuction, kGray-1, &srcRect );
- while( monitor >= 6 )
- {
- myRect.right += kBlobHorizSize;
- SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
- myRect.left = myRect.right;
-
- monitor -= 6;
- }
-
- if( monitor > 0 )
- {
- myRect.right += kBlobHorizSize;
- SurfaceDrawAlpha( &myRect, kGray, kLight, smallGrayList[monitor] );
- myRect.left = myRect.right;
- myRect.right += kBlobHorizSize;
- SurfaceDrawAlpha( &myRect, kGray, kLight, smallGrayList[monitor]+1 );
- }
-
- SDLU_ReleaseSurface( smallGrayDrawSurface );
-
- SDLU_BlitFrontSurface( smallGrayDrawSurface,
- SDLU_MRectToSDLRect( &grayMonitorZRect, &sourceSDLRect ),
- SDLU_MRectToSDLRect( &grayMonitorRect[player], &destSDLRect ) );
- }
-}
--- /dev/null
+++ b/src/grays.c
@@ -1,0 +1,372 @@
+// grays.c
+
+#include "SDLU.h"
+
+#include "main.h"
+#include "grays.h"
+#include "players.h"
+#include "graphics.h"
+#include "gworld.h"
+#include "control.h"
+#include "soundfx.h"
+#include "score.h"
+#include "random.h"
+#include "graymonitor.h"
+#include "gameticks.h"
+#include "blitter.h"
+#include "zap.h"
+#include "level.h"
+#include "opponent.h"
+
+int grays[2][kGridAcross], grayAir[2][kGridAcross];
+int unallocatedGrays[2], lockGrays[2], rowBounce[2][kGridAcross], splat[2][kGridAcross];
+MTicks blinkTime[2];
+int blinkStage[2];
+const int blinkList[] = { kGrayNoBlink, kGrayBlink1, kGrayBlink2,
+ kGrayBlink3, kGrayBlink2, kGrayBlink1 };
+
+void InitGrays( void )
+{
+ int player, gridX;
+
+ blinkTime[0] = GameTickCount( );
+ blinkTime[1] = GameTickCount( ) + 60;
+
+ for( player=0; player<=1; player++ )
+ {
+ blinkStage[player] = 0;
+ unallocatedGrays[player] = 0;
+
+ for( gridX=0; gridX<kGridAcross; gridX++ )
+ {
+ grays[player][gridX] = 0;
+ rowBounce[player][gridX] = -1;
+ }
+ }
+}
+
+void BlinkGrays( int player )
+{
+ int x, y, currentBlinkGraphic;
+ MRect myRect;
+
+ if( blinkTime[player] > GameTickCount( ) )
+ return;
+
+ blinkTime[player] += 2;
+ blinkStage[player]++;
+
+ if( blinkStage[player] > 5 )
+ {
+ blinkStage[player] = 0;
+ blinkTime[player] = GameTickCount( ) + kTimeBetweenBlinks;
+ }
+
+ currentBlinkGraphic = blinkList[ blinkStage[player] ];
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ if( rowBounce[player][x] == -1 )
+ {
+ for( y=kGridDown-1; y>=0; y-- )
+ {
+ if( (grid[player][x][y] == kGray) &&
+ (suction[player][x][y] == kGrayNoBlink) )
+ {
+ CalcBlobRect( x, y, &myRect );
+ SurfaceDrawBoard( player, &myRect );
+ SurfaceDrawAlpha( &myRect, kGray, kLight, currentBlinkGraphic );
+ CleanSpriteArea( player, &myRect );
+ }
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+}
+
+void CalculateGrays( int player, int blobsToDrop )
+{
+ if( blobsToDrop < unallocatedGrays[1-player] )
+ {
+ unallocatedGrays[1-player] -= blobsToDrop;
+ lockGrays[1-player] -= blobsToDrop;
+ if( lockGrays[1-player] < 0 ) lockGrays[1-player] = 0;
+
+ blobsToDrop = 0;
+ ShowGrayMonitor( 1-player );
+ }
+ else
+ {
+ blobsToDrop -= unallocatedGrays[1-player];
+ unallocatedGrays[1-player] = 0;
+ lockGrays[1-player] = 0;
+ ShowGrayMonitor( 1-player );
+
+ unallocatedGrays[player] += blobsToDrop;
+ ShowGrayMonitor( player );
+ }
+}
+
+void LockGrays( int player )
+{
+ lockGrays[player] = unallocatedGrays[player];
+}
+
+void SetupGrays( int player )
+{
+ int grayX, change;
+ MBoolean onlyOnce[kGridAcross];
+ int rowFree[kGridAcross];
+
+ if( role[player] == kDropGrays ) return; // next time around
+
+ for( grayX=0; grayX < kGridAcross; grayX++ )
+ {
+ grayAir[player][grayX] = -RandomBefore(kBlobVertSize*3/2);
+ rowFree[grayX] = -1;
+
+ while( grid[player][grayX][rowFree[grayX]+1] == kEmpty &&
+ rowFree[grayX] < (kGridDown-1) )
+ rowFree[grayX]++;
+ }
+
+ while( lockGrays[player] >= kGridAcross )
+ {
+ change = 0;
+
+ for( grayX=0; grayX < kGridAcross; grayX++ )
+ {
+ if( rowFree[grayX] >= 0 )
+ {
+ grays[player][grayX]++;
+ //grayAir[player][grayX] -= kBlobVertSize;
+ rowFree[grayX]--;
+ change++;
+ }
+ }
+
+ lockGrays[player] -= change;
+ unallocatedGrays[player] -= change;
+
+ if( change == 0 ) break;
+ }
+
+ if( lockGrays[player] > 0 )
+ {
+ for( grayX = 0; grayX < kGridAcross; grayX++ )
+ {
+ onlyOnce[grayX] = rowFree[grayX] > 0;
+ }
+
+ while( (onlyOnce[0] || onlyOnce[1] || onlyOnce[2] ||
+ onlyOnce[3] || onlyOnce[4] || onlyOnce[5]) &&
+ (lockGrays[player] > 0) )
+ {
+ grayX = RandomBefore(kGridAcross);
+
+ if( onlyOnce[grayX] )
+ {
+ grays[player][grayX]++;
+ //grayAir[player][grayX] -= kBlobVertSize;
+ lockGrays[player]--;
+ unallocatedGrays[player]--;
+ onlyOnce[grayX] = false;
+ }
+ }
+ }
+}
+
+void DropGrays( int player )
+{
+ MRect myRect;
+ int count, grayX;
+
+ if( blobTime[player] > GameTickCount( ) )
+ return;
+
+ blobTime[player]++;
+
+ for( grayX = 0; grayX < kGridAcross; grayX++ )
+ {
+ if( grays[player][grayX] > 0 )
+ {
+ myRect.bottom = grayAir[player][grayX];
+ myRect.left = kBlobHorizSize * grayX;
+ myRect.top = myRect.bottom - (kBlobVertSize * grays[player][grayX]);
+ myRect.right = myRect.left + kBlobHorizSize;
+ CleanSpriteArea( player, &myRect );
+
+ grayAir[player][grayX] += 4;
+ if( grayAir[player][grayX] > 0 ) grayAir[player][grayX] += grayAir[player][grayX] / 12;
+
+ if( ( grayAir[player][grayX] / kBlobVertSize ) >= GetRowHeight( player, grayX ) )
+ {
+ PlaceGrayRow( player, grayX );
+ ShowGrayMonitor( player );
+ }
+ else
+ {
+ myRect.top = grayAir[player][grayX];
+ myRect.bottom = myRect.top + kBlobVertSize;
+
+ SDLU_AcquireSurface( playerSpriteSurface[player] );
+
+ for( count=0; count<grays[player][grayX]; count++ )
+ {
+ OffsetMRect( &myRect, 0, -kBlobVertSize );
+ CleanSpriteArea( player, &myRect );
+ SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
+ }
+
+ SDLU_ReleaseSurface( playerSpriteSurface[player] );
+ }
+ }
+ }
+
+ Bounce( player );
+
+ if( !BusyDroppingGrays( player ) )
+ {
+ role[player] = kWaitForRetrieval;
+ }
+}
+
+MBoolean BusyDroppingGrays( int player )
+{
+ int grayX;
+
+ for( grayX = 0; grayX<kGridAcross; grayX++ )
+ {
+ if( rowBounce[player][grayX] >= 0 ||
+ grays[player][grayX] > 0 )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void PlaceGrayRow( int player, int grayX )
+{
+ int grayY;
+ MRect myRect;
+
+ if( player == 1 ) OpponentPissed( );
+
+ rowBounce[player][grayX] = 0;
+ splat[player][grayX] = GetRowHeight( player, grayX )+1;
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ while( grays[player][grayX] > 0 )
+ {
+ grayY = GetRowHeight( player, grayX );
+
+ grid[player][grayX][grayY] = kGray;
+ suction[player][grayX][grayY] = kGrayNoBlink;
+
+ CalcBlobRect( grayX, grayY, &myRect );
+ SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
+ CleanSpriteArea( player, &myRect );
+
+ grays[player][grayX]--;
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+
+ PlayStereoFrequency( player, kBounce, player );
+}
+
+void Bounce( int player )
+{
+ int x, y, bounce, suck, blob, rows, currentBlinkGraphic;
+ MRect blobRect;
+ double blobTop, compress;
+ const double compressList[kZapFrames+1] = {
+ -kBlobVertSize + 0.83,
+ -kBlobVertSize + 1.58,
+ -kBlobVertSize + 2.22,
+ -kBlobVertSize + 2.76,
+ -kBlobVertSize + 3.20,
+ -kBlobVertSize + 3.55,
+ -kBlobVertSize + 3.80,
+ -kBlobVertSize + 3.95,
+ -kBlobVertSize + 4.00,
+ -kBlobVertSize + 3.95,
+ -kBlobVertSize + 3.80,
+ -kBlobVertSize + 3.55,
+ -kBlobVertSize + 3.20,
+ -kBlobVertSize + 2.76,
+ -kBlobVertSize + 2.22,
+ -kBlobVertSize + 1.58,
+ -kBlobVertSize + 0.83,
+ -kBlobVertSize,
+ -kBlobVertSize,
+ -kBlobVertSize,
+ -kBlobVertSize
+ };
+
+ currentBlinkGraphic = blinkList[ blinkStage[player] ];
+
+ SDLU_AcquireSurface( playerSpriteSurface[player] );
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ if( rowBounce[player][x] >= 0 ) CleanSplat( player, x, splat[player][x], rowBounce[player][x] );
+ }
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ bounce = rowBounce[player][x];
+ if( bounce >= 0 )
+ {
+ compress = compressList[bounce];
+ rows = GetRowHeight( player, x );
+
+ CalcBlobRect( x, rows, &blobRect );
+ blobRect.bottom = kBlobVertSize * kGridDown;
+ SurfaceDrawBoard( player, &blobRect );
+ SetUpdateRect( player, &blobRect );
+
+ blobRect.top = kBlobVertSize * (kGridDown-1);
+ blobTop = kBlobVertSize * (kGridDown-1);
+
+ for( y=kGridDown-1; y>=rows; y-- )
+ {
+ suck = suction[player][x][y];
+ blob = grid[player][x][y];
+ if( suck == kNoSuction && blob >= kFirstBlob &&
+ blob <= kLastBlob && compress > (-kBlobVertSize + 3) )
+ {
+ suck = kSquish;
+ }
+
+ if( blob == kGray ) SurfaceDrawAlpha( &blobRect, kGray, kLight, currentBlinkGraphic );
+ else SurfaceDrawBlob( player, &blobRect, blob, suck, charred[player][x][y] );
+
+ blobTop += compress;
+ blobRect.top = (short) blobTop;
+ blobRect.bottom = blobRect.top + kBlobVertSize;
+ }
+ }
+ }
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ if( rowBounce[player][x] >= 0 ) DrawSplat( player, x, splat[player][x], rowBounce[player][x] );
+ }
+
+ SDLU_ReleaseSurface( playerSpriteSurface[player] );
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ if( rowBounce[player][x] >= 0 && rowBounce[player][x] < (kZapFrames) )
+ rowBounce[player][x]++;
+ else
+ rowBounce[player][x] = -1;
+ }
+}
--- a/src/grays.cpp
+++ /dev/null
@@ -1,372 +1,0 @@
-// grays.c
-
-#include "SDLU.h"
-
-#include "main.h"
-#include "grays.h"
-#include "players.h"
-#include "graphics.h"
-#include "gworld.h"
-#include "control.h"
-#include "soundfx.h"
-#include "score.h"
-#include "random.h"
-#include "graymonitor.h"
-#include "gameticks.h"
-#include "blitter.h"
-#include "zap.h"
-#include "level.h"
-#include "opponent.h"
-
-int grays[2][kGridAcross], grayAir[2][kGridAcross];
-int unallocatedGrays[2], lockGrays[2], rowBounce[2][kGridAcross], splat[2][kGridAcross];
-MTicks blinkTime[2];
-int blinkStage[2];
-const int blinkList[] = { kGrayNoBlink, kGrayBlink1, kGrayBlink2,
- kGrayBlink3, kGrayBlink2, kGrayBlink1 };
-
-void InitGrays( void )
-{
- int player, gridX;
-
- blinkTime[0] = GameTickCount( );
- blinkTime[1] = GameTickCount( ) + 60;
-
- for( player=0; player<=1; player++ )
- {
- blinkStage[player] = 0;
- unallocatedGrays[player] = 0;
-
- for( gridX=0; gridX<kGridAcross; gridX++ )
- {
- grays[player][gridX] = 0;
- rowBounce[player][gridX] = -1;
- }
- }
-}
-
-void BlinkGrays( int player )
-{
- int x, y, currentBlinkGraphic;
- MRect myRect;
-
- if( blinkTime[player] > GameTickCount( ) )
- return;
-
- blinkTime[player] += 2;
- blinkStage[player]++;
-
- if( blinkStage[player] > 5 )
- {
- blinkStage[player] = 0;
- blinkTime[player] = GameTickCount( ) + kTimeBetweenBlinks;
- }
-
- currentBlinkGraphic = blinkList[ blinkStage[player] ];
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- for( x=0; x<kGridAcross; x++ )
- {
- if( rowBounce[player][x] == -1 )
- {
- for( y=kGridDown-1; y>=0; y-- )
- {
- if( (grid[player][x][y] == kGray) &&
- (suction[player][x][y] == kGrayNoBlink) )
- {
- CalcBlobRect( x, y, &myRect );
- SurfaceDrawBoard( player, &myRect );
- SurfaceDrawAlpha( &myRect, kGray, kLight, currentBlinkGraphic );
- CleanSpriteArea( player, &myRect );
- }
- }
- }
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-}
-
-void CalculateGrays( int player, int blobsToDrop )
-{
- if( blobsToDrop < unallocatedGrays[1-player] )
- {
- unallocatedGrays[1-player] -= blobsToDrop;
- lockGrays[1-player] -= blobsToDrop;
- if( lockGrays[1-player] < 0 ) lockGrays[1-player] = 0;
-
- blobsToDrop = 0;
- ShowGrayMonitor( 1-player );
- }
- else
- {
- blobsToDrop -= unallocatedGrays[1-player];
- unallocatedGrays[1-player] = 0;
- lockGrays[1-player] = 0;
- ShowGrayMonitor( 1-player );
-
- unallocatedGrays[player] += blobsToDrop;
- ShowGrayMonitor( player );
- }
-}
-
-void LockGrays( int player )
-{
- lockGrays[player] = unallocatedGrays[player];
-}
-
-void SetupGrays( int player )
-{
- int grayX, change;
- MBoolean onlyOnce[kGridAcross];
- int rowFree[kGridAcross];
-
- if( role[player] == kDropGrays ) return; // next time around
-
- for( grayX=0; grayX < kGridAcross; grayX++ )
- {
- grayAir[player][grayX] = -RandomBefore(kBlobVertSize*3/2);
- rowFree[grayX] = -1;
-
- while( grid[player][grayX][rowFree[grayX]+1] == kEmpty &&
- rowFree[grayX] < (kGridDown-1) )
- rowFree[grayX]++;
- }
-
- while( lockGrays[player] >= kGridAcross )
- {
- change = 0;
-
- for( grayX=0; grayX < kGridAcross; grayX++ )
- {
- if( rowFree[grayX] >= 0 )
- {
- grays[player][grayX]++;
- //grayAir[player][grayX] -= kBlobVertSize;
- rowFree[grayX]--;
- change++;
- }
- }
-
- lockGrays[player] -= change;
- unallocatedGrays[player] -= change;
-
- if( change == 0 ) break;
- }
-
- if( lockGrays[player] > 0 )
- {
- for( grayX = 0; grayX < kGridAcross; grayX++ )
- {
- onlyOnce[grayX] = rowFree[grayX] > 0;
- }
-
- while( (onlyOnce[0] || onlyOnce[1] || onlyOnce[2] ||
- onlyOnce[3] || onlyOnce[4] || onlyOnce[5]) &&
- (lockGrays[player] > 0) )
- {
- grayX = RandomBefore(kGridAcross);
-
- if( onlyOnce[grayX] )
- {
- grays[player][grayX]++;
- //grayAir[player][grayX] -= kBlobVertSize;
- lockGrays[player]--;
- unallocatedGrays[player]--;
- onlyOnce[grayX] = false;
- }
- }
- }
-}
-
-void DropGrays( int player )
-{
- MRect myRect;
- int count, grayX;
-
- if( blobTime[player] > GameTickCount( ) )
- return;
-
- blobTime[player]++;
-
- for( grayX = 0; grayX < kGridAcross; grayX++ )
- {
- if( grays[player][grayX] > 0 )
- {
- myRect.bottom = grayAir[player][grayX];
- myRect.left = kBlobHorizSize * grayX;
- myRect.top = myRect.bottom - (kBlobVertSize * grays[player][grayX]);
- myRect.right = myRect.left + kBlobHorizSize;
- CleanSpriteArea( player, &myRect );
-
- grayAir[player][grayX] += 4;
- if( grayAir[player][grayX] > 0 ) grayAir[player][grayX] += grayAir[player][grayX] / 12;
-
- if( ( grayAir[player][grayX] / kBlobVertSize ) >= GetRowHeight( player, grayX ) )
- {
- PlaceGrayRow( player, grayX );
- ShowGrayMonitor( player );
- }
- else
- {
- myRect.top = grayAir[player][grayX];
- myRect.bottom = myRect.top + kBlobVertSize;
-
- SDLU_AcquireSurface( playerSpriteSurface[player] );
-
- for( count=0; count<grays[player][grayX]; count++ )
- {
- OffsetMRect( &myRect, 0, -kBlobVertSize );
- CleanSpriteArea( player, &myRect );
- SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
- }
-
- SDLU_ReleaseSurface( playerSpriteSurface[player] );
- }
- }
- }
-
- Bounce( player );
-
- if( !BusyDroppingGrays( player ) )
- {
- role[player] = kWaitForRetrieval;
- }
-}
-
-MBoolean BusyDroppingGrays( int player )
-{
- int grayX;
-
- for( grayX = 0; grayX<kGridAcross; grayX++ )
- {
- if( rowBounce[player][grayX] >= 0 ||
- grays[player][grayX] > 0 )
- {
- return true;
- }
- }
-
- return false;
-}
-
-void PlaceGrayRow( int player, int grayX )
-{
- int grayY;
- MRect myRect;
-
- if( player == 1 ) OpponentPissed( );
-
- rowBounce[player][grayX] = 0;
- splat[player][grayX] = GetRowHeight( player, grayX )+1;
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- while( grays[player][grayX] > 0 )
- {
- grayY = GetRowHeight( player, grayX );
-
- grid[player][grayX][grayY] = kGray;
- suction[player][grayX][grayY] = kGrayNoBlink;
-
- CalcBlobRect( grayX, grayY, &myRect );
- SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
- CleanSpriteArea( player, &myRect );
-
- grays[player][grayX]--;
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-
- PlayStereoFrequency( player, kBounce, player );
-}
-
-void Bounce( int player )
-{
- int x, y, bounce, suck, blob, rows, currentBlinkGraphic;
- MRect blobRect;
- double blobTop, compress;
- const double compressList[kZapFrames+1] = {
- -kBlobVertSize + 0.83,
- -kBlobVertSize + 1.58,
- -kBlobVertSize + 2.22,
- -kBlobVertSize + 2.76,
- -kBlobVertSize + 3.20,
- -kBlobVertSize + 3.55,
- -kBlobVertSize + 3.80,
- -kBlobVertSize + 3.95,
- -kBlobVertSize + 4.00,
- -kBlobVertSize + 3.95,
- -kBlobVertSize + 3.80,
- -kBlobVertSize + 3.55,
- -kBlobVertSize + 3.20,
- -kBlobVertSize + 2.76,
- -kBlobVertSize + 2.22,
- -kBlobVertSize + 1.58,
- -kBlobVertSize + 0.83,
- -kBlobVertSize,
- -kBlobVertSize,
- -kBlobVertSize,
- -kBlobVertSize
- };
-
- currentBlinkGraphic = blinkList[ blinkStage[player] ];
-
- SDLU_AcquireSurface( playerSpriteSurface[player] );
-
- for( x=0; x<kGridAcross; x++ )
- {
- if( rowBounce[player][x] >= 0 ) CleanSplat( player, x, splat[player][x], rowBounce[player][x] );
- }
-
- for( x=0; x<kGridAcross; x++ )
- {
- bounce = rowBounce[player][x];
- if( bounce >= 0 )
- {
- compress = compressList[bounce];
- rows = GetRowHeight( player, x );
-
- CalcBlobRect( x, rows, &blobRect );
- blobRect.bottom = kBlobVertSize * kGridDown;
- SurfaceDrawBoard( player, &blobRect );
- SetUpdateRect( player, &blobRect );
-
- blobRect.top = kBlobVertSize * (kGridDown-1);
- blobTop = kBlobVertSize * (kGridDown-1);
-
- for( y=kGridDown-1; y>=rows; y-- )
- {
- suck = suction[player][x][y];
- blob = grid[player][x][y];
- if( suck == kNoSuction && blob >= kFirstBlob &&
- blob <= kLastBlob && compress > (-kBlobVertSize + 3) )
- {
- suck = kSquish;
- }
-
- if( blob == kGray ) SurfaceDrawAlpha( &blobRect, kGray, kLight, currentBlinkGraphic );
- else SurfaceDrawBlob( player, &blobRect, blob, suck, charred[player][x][y] );
-
- blobTop += compress;
- blobRect.top = (short) blobTop;
- blobRect.bottom = blobRect.top + kBlobVertSize;
- }
- }
- }
-
- for( x=0; x<kGridAcross; x++ )
- {
- if( rowBounce[player][x] >= 0 ) DrawSplat( player, x, splat[player][x], rowBounce[player][x] );
- }
-
- SDLU_ReleaseSurface( playerSpriteSurface[player] );
-
- for( x=0; x<kGridAcross; x++ )
- {
- if( rowBounce[player][x] >= 0 && rowBounce[player][x] < (kZapFrames) )
- rowBounce[player][x]++;
- else
- rowBounce[player][x] = -1;
- }
-}
--- /dev/null
+++ b/src/gworld.c
@@ -1,0 +1,243 @@
+// gworld.c
+
+#include "SDLU.h"
+
+#include "main.h"
+#include "gworld.h"
+#include "blitter.h"
+#include "graphics.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define STBI_ONLY_JPEG
+#define STBI_ONLY_PNG
+#define STB_IMAGE_IMPLEMENTATION
+#include "support/stb_image.h"
+
+SDL_Surface* blobSurface;
+SDL_Surface* maskSurface;
+SDL_Surface* charMaskSurface;
+SDL_Surface* boardSurface[2];
+SDL_Surface* blastSurface;
+SDL_Surface* blastMaskSurface;
+SDL_Surface* playerSurface[2];
+SDL_Surface* playerSpriteSurface[2];
+
+
+void GetBlobGraphics()
+{
+ MRect myRect;
+
+ // Get board
+
+ myRect.top = myRect.left = 0;
+ myRect.right = kBlobHorizSize * kGridAcross;
+ myRect.bottom = kBlobVertSize * (kGridDown-1);
+
+ boardSurface[0] = LoadPICTAsSurface( picBoard, 32 );
+
+ boardSurface[1] = LoadPICTAsSurface( picBoardRight, 32 );
+ if( boardSurface[1] == NULL )
+ boardSurface[1] = LoadPICTAsSurface( picBoard, 32 );
+
+ // Get blob worlds
+ blobSurface = LoadPICTAsSurface( picBlob, 32 );
+ maskSurface = LoadPICTAsSurface( picBlobMask, MASK_DEPTH );
+ charMaskSurface = LoadPICTAsSurface( picCharMask, MASK_DEPTH );
+
+ // Get blast worlds
+
+ blastSurface = LoadPICTAsSurface( picBlast, 32 );
+ blastMaskSurface = LoadPICTAsSurface( picBlastMask, 32 );
+}
+
+
+void InitPlayerWorlds()
+{
+ MRect myRect;
+ SDL_Rect sdlRect;
+ int count;
+
+ myRect.top = myRect.left = 0;
+ myRect.right = kGridAcross * kBlobHorizSize;
+ myRect.bottom = kGridDown * kBlobVertSize;
+
+ SDLU_MRectToSDLRect( &myRect, &sdlRect );
+
+ for( count=0; count<=1; count++ )
+ {
+ playerSurface[count] = SDLU_InitSurface( &sdlRect, 32 );
+ playerSpriteSurface[count] = SDLU_InitSurface( &sdlRect, 32 );
+ }
+}
+
+
+void SurfaceDrawBoard( int player, const MRect *myRect )
+{
+ MRect srcRect, offsetRect;
+ SDL_Rect srcSDLRect, offsetSDLRect;
+
+ srcRect = *myRect;
+ if( srcRect.bottom <= kBlobVertSize ) return;
+ if( srcRect.top < kBlobVertSize ) srcRect.top = kBlobVertSize;
+
+ offsetRect = srcRect;
+ OffsetMRect( &offsetRect, 0, -kBlobVertSize );
+
+ SDLU_BlitSurface( boardSurface[player], SDLU_MRectToSDLRect( &offsetRect, &offsetSDLRect ),
+ SDLU_GetCurrentSurface(), SDLU_MRectToSDLRect( &srcRect, &srcSDLRect ) );
+}
+
+
+void SurfaceDrawBlob( int player, const MRect *myRect, int blob, int state, int charred )
+{
+ SurfaceDrawBoard( player, myRect );
+ SurfaceDrawSprite( myRect, blob, state );
+
+ if( charred & 0x0F )
+ {
+ MRect blobRect, charRect, alphaRect;
+
+ CalcBlobRect( (charred & 0x0F), kBombTop-1, &charRect );
+ CalcBlobRect( (charred & 0x0F), kBombBottom-1, &alphaRect );
+ CalcBlobRect( state, blob-1, &blobRect );
+
+ SurfaceBlitWeightedDualAlpha( SDLU_GetCurrentSurface(), blobSurface, charMaskSurface, blobSurface, SDLU_GetCurrentSurface(),
+ myRect, &charRect, &blobRect, &alphaRect, myRect,
+ (charred & 0xF0) );
+ }
+}
+
+void SurfaceDrawShadow( const MRect *myRect, int blob, int state )
+{
+ int x;
+ const MPoint offset[4] = { {-2, 0}, {0, -2}, {2, 0}, {0, 2} };
+
+ if( blob > kEmpty )
+ {
+ MRect blobRect, destRect;
+
+ for( x=0; x<4; x++ )
+ {
+ destRect = *myRect;
+ OffsetMRect( &destRect, offset[x].h, offset[x].v );
+
+ CalcBlobRect( state, blob-1, &blobRect );
+ SurfaceBlitColor( maskSurface, SDLU_GetCurrentSurface(),
+ &blobRect, &destRect,
+ 0, 0, 0, _5TO8(3) );
+ }
+ }
+}
+
+void SurfaceDrawColor( const MRect *myRect, int blob, int state, int r, int g, int b, int w )
+{
+ MRect blobRect;
+ if( blob > kEmpty )
+ {
+ CalcBlobRect( state, blob-1, &blobRect );
+ SurfaceBlitColor( charMaskSurface, SDLU_GetCurrentSurface(),
+ &blobRect, myRect,
+ r, g, b, w );
+ }
+}
+
+void SurfaceDrawAlpha( const MRect *myRect, int blob, int mask, int state )
+{
+ if( blob > kEmpty )
+ {
+ MRect blobRect, alphaRect;
+
+ CalcBlobRect( state, blob-1, &blobRect );
+ CalcBlobRect( state, mask-1, &alphaRect );
+
+ SurfaceBlitAlpha( SDLU_GetCurrentSurface(), blobSurface, blobSurface, SDLU_GetCurrentSurface(),
+ myRect, &blobRect, &alphaRect, myRect );
+ }
+}
+
+void SurfaceDrawSprite( const MRect *myRect, int blob, int state )
+{
+ MRect blobRect;
+ if( blob > kEmpty )
+ {
+ CalcBlobRect( state, blob-1, &blobRect );
+ SurfaceBlitBlob( &blobRect, myRect );
+ }
+}
+
+
+MBoolean PICTExists( int pictID )
+{
+ if( FileExists( QuickResourceName( "PICT", pictID, ".jpg" ) ) )
+ return true;
+
+ if( FileExists( QuickResourceName( "PICT", pictID, ".png" ) ) )
+ return true;
+
+ return false;
+}
+
+
+SDL_Surface* LoadPICTAsSurface( int pictID, int depth )
+{
+ const char* filename;
+ SDL_Surface* surface;
+ SDL_Rect rect = {0};
+ uint8_t* pixels = NULL;
+
+ filename = QuickResourceName( "PICT", pictID, ".jpg" );
+ if( !FileExists( filename ) )
+ {
+ filename = QuickResourceName( "PICT", pictID, ".png" );
+ }
+ if( !FileExists( filename ) )
+ {
+ return NULL;
+ }
+
+ pixels = stbi_load(filename, &rect.w, &rect.h, NULL, 3);
+
+ surface = SDLU_InitSurface(&rect, 32);
+ SDL_LockSurface(surface);
+
+ uint8_t* srcPixels = pixels;
+ uint8_t* destPixels = (uint8_t*) surface->pixels;
+ for (int i = 0; i < rect.w*rect.h; i++)
+ {
+ destPixels[0] = srcPixels[2];
+ destPixels[1] = srcPixels[1];
+ destPixels[2] = srcPixels[0];
+ destPixels[3] = 0xFF;
+ destPixels += 4;
+ srcPixels += 3;
+ }
+
+ SDL_UnlockSurface(surface);
+
+ free(pixels);
+ pixels = NULL;
+
+ if( depth != 0 )
+ {
+ SDLU_ChangeSurfaceDepth( &surface, depth );
+ }
+
+ return surface;
+}
+
+void DrawPICTInSurface( SDL_Surface* surface, int pictID )
+{
+ SDL_Surface* image;
+
+ image = LoadPICTAsSurface( pictID, 0 );
+ if( image != NULL )
+ {
+ SDLU_BlitSurface( image, &image->clip_rect,
+ surface, &surface->clip_rect );
+
+ SDL_FreeSurface( image );
+ }
+}
--- a/src/gworld.cpp
+++ /dev/null
@@ -1,243 +1,0 @@
-// gworld.c
-
-#include "SDLU.h"
-
-#include "main.h"
-#include "gworld.h"
-#include "blitter.h"
-#include "graphics.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define STBI_ONLY_JPEG
-#define STBI_ONLY_PNG
-#define STB_IMAGE_IMPLEMENTATION
-#include "support/stb_image.h"
-
-SDL_Surface* blobSurface;
-SDL_Surface* maskSurface;
-SDL_Surface* charMaskSurface;
-SDL_Surface* boardSurface[2];
-SDL_Surface* blastSurface;
-SDL_Surface* blastMaskSurface;
-SDL_Surface* playerSurface[2];
-SDL_Surface* playerSpriteSurface[2];
-
-
-void GetBlobGraphics()
-{
- MRect myRect;
-
- // Get board
-
- myRect.top = myRect.left = 0;
- myRect.right = kBlobHorizSize * kGridAcross;
- myRect.bottom = kBlobVertSize * (kGridDown-1);
-
- boardSurface[0] = LoadPICTAsSurface( picBoard, 32 );
-
- boardSurface[1] = LoadPICTAsSurface( picBoardRight, 32 );
- if( boardSurface[1] == NULL )
- boardSurface[1] = LoadPICTAsSurface( picBoard, 32 );
-
- // Get blob worlds
- blobSurface = LoadPICTAsSurface( picBlob, 32 );
- maskSurface = LoadPICTAsSurface( picBlobMask, MASK_DEPTH );
- charMaskSurface = LoadPICTAsSurface( picCharMask, MASK_DEPTH );
-
- // Get blast worlds
-
- blastSurface = LoadPICTAsSurface( picBlast, 32 );
- blastMaskSurface = LoadPICTAsSurface( picBlastMask, 32 );
-}
-
-
-void InitPlayerWorlds()
-{
- MRect myRect;
- SDL_Rect sdlRect;
- int count;
-
- myRect.top = myRect.left = 0;
- myRect.right = kGridAcross * kBlobHorizSize;
- myRect.bottom = kGridDown * kBlobVertSize;
-
- SDLU_MRectToSDLRect( &myRect, &sdlRect );
-
- for( count=0; count<=1; count++ )
- {
- playerSurface[count] = SDLU_InitSurface( &sdlRect, 32 );
- playerSpriteSurface[count] = SDLU_InitSurface( &sdlRect, 32 );
- }
-}
-
-
-void SurfaceDrawBoard( int player, const MRect *myRect )
-{
- MRect srcRect, offsetRect;
- SDL_Rect srcSDLRect, offsetSDLRect;
-
- srcRect = *myRect;
- if( srcRect.bottom <= kBlobVertSize ) return;
- if( srcRect.top < kBlobVertSize ) srcRect.top = kBlobVertSize;
-
- offsetRect = srcRect;
- OffsetMRect( &offsetRect, 0, -kBlobVertSize );
-
- SDLU_BlitSurface( boardSurface[player], SDLU_MRectToSDLRect( &offsetRect, &offsetSDLRect ),
- SDLU_GetCurrentSurface(), SDLU_MRectToSDLRect( &srcRect, &srcSDLRect ) );
-}
-
-
-void SurfaceDrawBlob( int player, const MRect *myRect, int blob, int state, int charred )
-{
- SurfaceDrawBoard( player, myRect );
- SurfaceDrawSprite( myRect, blob, state );
-
- if( charred & 0x0F )
- {
- MRect blobRect, charRect, alphaRect;
-
- CalcBlobRect( (charred & 0x0F), kBombTop-1, &charRect );
- CalcBlobRect( (charred & 0x0F), kBombBottom-1, &alphaRect );
- CalcBlobRect( state, blob-1, &blobRect );
-
- SurfaceBlitWeightedDualAlpha( SDLU_GetCurrentSurface(), blobSurface, charMaskSurface, blobSurface, SDLU_GetCurrentSurface(),
- myRect, &charRect, &blobRect, &alphaRect, myRect,
- (charred & 0xF0) );
- }
-}
-
-void SurfaceDrawShadow( const MRect *myRect, int blob, int state )
-{
- int x;
- const MPoint offset[4] = { {-2, 0}, {0, -2}, {2, 0}, {0, 2} };
-
- if( blob > kEmpty )
- {
- MRect blobRect, destRect;
-
- for( x=0; x<4; x++ )
- {
- destRect = *myRect;
- OffsetMRect( &destRect, offset[x].h, offset[x].v );
-
- CalcBlobRect( state, blob-1, &blobRect );
- SurfaceBlitColor( maskSurface, SDLU_GetCurrentSurface(),
- &blobRect, &destRect,
- 0, 0, 0, _5TO8(3) );
- }
- }
-}
-
-void SurfaceDrawColor( const MRect *myRect, int blob, int state, int r, int g, int b, int w )
-{
- MRect blobRect;
- if( blob > kEmpty )
- {
- CalcBlobRect( state, blob-1, &blobRect );
- SurfaceBlitColor( charMaskSurface, SDLU_GetCurrentSurface(),
- &blobRect, myRect,
- r, g, b, w );
- }
-}
-
-void SurfaceDrawAlpha( const MRect *myRect, int blob, int mask, int state )
-{
- if( blob > kEmpty )
- {
- MRect blobRect, alphaRect;
-
- CalcBlobRect( state, blob-1, &blobRect );
- CalcBlobRect( state, mask-1, &alphaRect );
-
- SurfaceBlitAlpha( SDLU_GetCurrentSurface(), blobSurface, blobSurface, SDLU_GetCurrentSurface(),
- myRect, &blobRect, &alphaRect, myRect );
- }
-}
-
-void SurfaceDrawSprite( const MRect *myRect, int blob, int state )
-{
- MRect blobRect;
- if( blob > kEmpty )
- {
- CalcBlobRect( state, blob-1, &blobRect );
- SurfaceBlitBlob( &blobRect, myRect );
- }
-}
-
-
-MBoolean PICTExists( int pictID )
-{
- if( FileExists( QuickResourceName( "PICT", pictID, ".jpg" ) ) )
- return true;
-
- if( FileExists( QuickResourceName( "PICT", pictID, ".png" ) ) )
- return true;
-
- return false;
-}
-
-
-SDL_Surface* LoadPICTAsSurface( int pictID, int depth )
-{
- const char* filename;
- SDL_Surface* surface;
- SDL_Rect rect = {};
- uint8_t* pixels = nullptr;
-
- filename = QuickResourceName( "PICT", pictID, ".jpg" );
- if( !FileExists( filename ) )
- {
- filename = QuickResourceName( "PICT", pictID, ".png" );
- }
- if( !FileExists( filename ) )
- {
- return nullptr;
- }
-
- pixels = stbi_load(filename, &rect.w, &rect.h, NULL, 3);
-
- surface = SDLU_InitSurface(&rect, 32);
- SDL_LockSurface(surface);
-
- uint8_t* srcPixels = pixels;
- uint8_t* destPixels = (uint8_t*) surface->pixels;
- for (int i = 0; i < rect.w*rect.h; i++)
- {
- destPixels[0] = srcPixels[2];
- destPixels[1] = srcPixels[1];
- destPixels[2] = srcPixels[0];
- destPixels[3] = 0xFF;
- destPixels += 4;
- srcPixels += 3;
- }
-
- SDL_UnlockSurface(surface);
-
- free(pixels);
- pixels = NULL;
-
- if( depth != 0 )
- {
- SDLU_ChangeSurfaceDepth( &surface, depth );
- }
-
- return surface;
-}
-
-void DrawPICTInSurface( SDL_Surface* surface, int pictID )
-{
- SDL_Surface* image;
-
- image = LoadPICTAsSurface( pictID, 0 );
- if( image != NULL )
- {
- SDLU_BlitSurface( image, &image->clip_rect,
- surface, &surface->clip_rect );
-
- SDL_FreeSurface( image );
- }
-}
--- /dev/null
+++ b/src/hiscore.c
@@ -1,0 +1,498 @@
+// hiscore.c
+
+#include "SDLU.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "main.h"
+#include "gworld.h"
+#include "graphics.h"
+#include "score.h"
+#include "hiscore.h"
+#include "keyselect.h"
+#include "font.h"
+#include "blitter.h"
+#include "random.h"
+#include "pause.h"
+#include "level.h"
+#include "tutorial.h"
+#include "graymonitor.h"
+#include "players.h"
+#include "gameticks.h"
+#include "music.h"
+#include "soundfx.h"
+
+Combo defaultBest =
+{
+ /*bestGrid[kGridAcross][kGridDown] = */
+ { { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty },
+ { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty },
+ { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, 1, 1, 1, 2, 2 },
+ { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, 1, 1 },
+ { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty },
+ { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty } },
+
+ /*bestA = */ 2,
+ /*bestB = */ 2,
+ /*bestM = */ false,
+ /*bestG = */ false,
+ /*bestLv = */ kTutorialLevel,
+ /*bestX = */ 1,
+ /*bestR = */ upRotate,
+ /*bestPlayer = */ 0,
+ /*bestValue = */ (40*1) + (50*9),
+ /*bestName = */ "Tutorial"
+};
+
+Combo best =
+{
+ /*bestGrid[kGridAcross][kGridDown] = */
+ { { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty },
+ { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty },
+ { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, 1, 1, 1, 2, 2 },
+ { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, 1, 1 },
+ { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty },
+ { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty } },
+
+ /*bestA = */ 2,
+ /*bestB = */ 2,
+ /*bestM = */ false,
+ /*bestG = */ false,
+ /*bestLv = */ kTutorialLevel,
+ /*bestX = */ 1,
+ /*bestR = */ upRotate,
+ /*bestPlayer = */ 0,
+ /*bestValue = */ (40*1) + (50*9),
+ /*bestName = */ "Tutorial"
+};
+
+Combo evenBetter = {0};
+Combo potentialCombo[2];
+
+AutoPattern hiScorePattern[] =
+{
+ { kIdleTicks, 60, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kBlockUntilComplete, 0, 0, NULL },
+ { kIdleTicks, 60, 0, NULL },
+ { kComplete, 0, 0, NULL }
+};
+
+HighScore scores[10] =
+{
+ {"Leviathan", 40000},
+ {"Dr. Crisis", 36000},
+ {"Angel", 32000},
+ {"Spike", 28000},
+ {"Fox", 24000},
+ {"Raguel", 20000},
+ {"Kumo", 16000},
+ {"Patty", 12000},
+ {"Yuurei", 8000},
+ {"Glurp", 4000}
+};
+
+HighScore defaultScores[10] =
+{
+ {"Leviathan", 40000},
+ {"Dr. Crisis", 36000},
+ {"Angel", 32000},
+ {"Spike", 28000},
+ {"Fox", 24000},
+ {"Raguel", 20000},
+ {"Kumo", 16000},
+ {"Patty", 12000},
+ {"Yuurei", 8000},
+ {"Glurp", 4000}
+};
+
+char highScoreName[256];
+const char *highScoreText;
+const char *highScoreRank;
+
+static void FadeScreen( SDL_Surface* hiScoreSurface, SDL_Surface* fadeSurface, int start, int end )
+{
+ MTicks timer;
+ int skip, frame, fade, color, direction, fadeStart, fadeEnd;
+ SDL_Rect destSDLRect;
+ SDL_Rect fullSDLRect = { 0, 0, 640, 480 };
+ int black;
+
+ black = SDL_MapRGB( fadeSurface->format, 0, 0, 0 );
+
+ if( start < end )
+ {
+ direction = 1;
+ fadeStart = 0;
+ fadeEnd = 32;
+ }
+ else
+ {
+ direction = -1;
+ fadeStart = 32;
+ fadeEnd = 0;
+ }
+
+ skip = 1;
+ timer = MTickCount( ) + 1;
+ while( timer > MTickCount() ) { }
+
+ for( frame = start; (direction>0)? (frame <= end): (frame >= end); frame += direction )
+ {
+ MRect drawRect = {0, 0, 15, 640};
+ timer += skip;
+
+ for( fade = fadeStart; fade != fadeEnd; fade += direction )
+ {
+ color = frame + fade;
+ if( color < 0 ) color = 0;
+ if( color > 31 ) color = 31;
+
+ SDLU_MRectToSDLRect( &drawRect, &destSDLRect );
+
+ switch( color )
+ {
+ case 0:
+ SDLU_BlitSurface( hiScoreSurface, &destSDLRect,
+ fadeSurface, &destSDLRect );
+ break;
+
+ case 31:
+ SDL_FillRect( fadeSurface, &destSDLRect, black );
+ break;
+
+ default:
+ SurfaceBlitColorOver( hiScoreSurface, fadeSurface,
+ &drawRect, &drawRect,
+ 0, 0, 0, _5TO8(color) );
+ break;
+ }
+
+ OffsetMRect( &drawRect, 0, 15 );
+ }
+
+ SDLU_BlitFrontSurface( fadeSurface, &fullSDLRect, &fullSDLRect );
+ SDLU_Present();
+
+ if( timer <= MTickCount( ) )
+ {
+ skip = 2;
+ }
+ else
+ {
+ skip = 1;
+ while( timer > MTickCount( ) )
+ {
+ SDLU_Yield();
+ }
+ }
+ }
+}
+
+void ShowHiscore( void )
+{
+ short count, length;
+ char myString[256];
+ int stringLength;
+ SDL_Surface* hiScoreSurface;
+ SDL_Surface* fadeSurface;
+ SDL_Rect fullSDLRect = { 0, 0, 640, 480 };
+ SkittlesFontPtr font;
+ SDL_Color anyColor;
+ MPoint dPoint;
+ const char* highScores = "HIGH SCORES";
+ int r, g, b;
+
+ if (DeleteKeyIsPressed())
+ {
+ // If the user holds delete while opening the high scores,
+ // clear the high score table.
+
+ memcpy( &scores, &defaultScores, sizeof( scores ) );
+ memcpy( &best, &defaultBest, sizeof( best ) );
+ }
+
+ hiScoreSurface = LoadPICTAsSurface( picBackdrop + (100 * RandomBefore(kLevels)), 32 );
+ fadeSurface = SDLU_InitSurface( &fullSDLRect, 32 );
+
+
+ SDLU_AcquireSurface( hiScoreSurface );
+
+ SDLU_GetPixel( hiScoreSurface, RandomBefore( fullSDLRect.w ), RandomBefore( fullSDLRect.h ), &anyColor );
+
+ anyColor.r = MinInt( 255, anyColor.r + 112 );
+ anyColor.g = MinInt( 255, anyColor.g + 112 );
+ anyColor.b = MinInt( 255, anyColor.b + 112 );
+
+ dPoint.v = widescreen? 100: 20;
+ dPoint.h = 225;
+ font = GetFont( picHiScoreFont );
+ for( count=0; highScores[count]; count++ )
+ {
+ SurfaceBlitCharacter( font, highScores[count], &dPoint, 255, 255, 255, 1 );
+ }
+
+ font = GetFont(widescreen ? picFont : picHiScoreFont);
+ for( count=0; count<=9; count++ )
+ {
+ r = ((255 * (10-count)) + (anyColor.r * count)) / 10;
+ g = ((255 * (10-count)) + (anyColor.g * count)) / 10;
+ b = ((255 * (10-count)) + (anyColor.b * count)) / 10;
+
+ if (widescreen)
+ dPoint.v = 150 + count * 24;
+ else
+ dPoint.v = 75 + count * 38;
+ dPoint.h = 85;
+
+ if( count<9 )
+ {
+ SurfaceBlitCharacter( font, count + '1', &dPoint, r, g, b, 1 );
+ }
+ else
+ {
+ SurfaceBlitCharacter( font, '1', &dPoint, r, g, b, 1 );
+ SurfaceBlitCharacter( font, '0', &dPoint, r, g, b, 1 );
+ }
+
+ SurfaceBlitCharacter( font, '.', &dPoint, r, g, b, 1 );
+ SurfaceBlitCharacter( font, ' ', &dPoint, r, g, b, 1 );
+
+ length = 0;
+ while( scores[count].name[length] && dPoint.h < 430 )
+ {
+ SurfaceBlitCharacter( font, scores[count].name[length++], &dPoint, r, g, b, 1 );
+ }
+
+ while( dPoint.h < 450 )
+ {
+ SurfaceBlitCharacter( font, '.', &dPoint, r, g, b, 1 );
+ }
+
+ dPoint.h = 470;
+
+ stringLength = sprintf( myString, "%d", scores[count].score );
+ for( length=0; length < stringLength; length++ )
+ {
+ SurfaceBlitCharacter( font, myString[length], &dPoint, r, g, b, 1 );
+ }
+ }
+
+ SDLU_ReleaseSurface( hiScoreSurface );
+
+ SDL_FillRect( g_frontSurface, &g_frontSurface->clip_rect, SDL_MapRGB( g_frontSurface->format, 0, 0, 0 ));
+ SDLU_Present();
+
+ SDLU_SetBrightness( 1.0f );
+
+ FadeScreen( hiScoreSurface, fadeSurface, 31, -32 );
+ do
+ {
+ }
+ while( !AnyKeyIsPressed( ) && !SDLU_Button() );
+ FadeScreen( hiScoreSurface, fadeSurface, -31, 32 );
+
+ SDLU_SetBrightness( 0.0f );
+
+ SDL_FreeSurface( hiScoreSurface );
+ SDL_FreeSurface( fadeSurface );
+}
+
+void InitPotentialCombos( void )
+{
+ memset( &potentialCombo[0], 0, sizeof(Combo) );
+ memset( &potentialCombo[1], 0, sizeof(Combo) );
+ potentialCombo[0].player = 0;
+ potentialCombo[1].player = 1;
+}
+
+void SubmitCombo( Combo *in )
+{
+ if( in->value > best.value && in->value > evenBetter.value )
+ {
+ PlayMono( kContinueSnd );
+ memcpy( &evenBetter, in, sizeof( Combo ) );
+ }
+}
+
+// Please note: This function may well be the biggest kludge in Candy Crisis.
+// It relies on tons of insider knowledge. But it works.
+void ShowBestCombo( void )
+{
+ SkittlesFontPtr font;
+ const char *bestCombo = "BEST COMBO";
+ const char *scan;
+ char bestInfo[256];
+ MPoint dPoint;
+ int levelCap;
+
+ StopBalloon( );
+ InitGame( kAutoControl, kNobodyControl );
+ scoreWindowVisible[0] = false;
+ grayMonitorVisible[0] = false;
+
+ level = best.lv;
+ levelCap = kLevels;
+ if( (level < 1 || level > levelCap) && level != kTutorialLevel )
+ {
+ memcpy( &best, &defaultBest, sizeof(best) );
+ showStartMenu = true;
+ return;
+ }
+
+ BeginRound( false );
+ character[0].dropSpeed = 12;
+
+ SDLU_AcquireSurface( backdropSurface );
+
+ font = GetFont(picHiScoreFont);
+ dPoint.v = widescreen? 70: 40;
+ dPoint.h = 225;
+ for( scan = bestCombo; *scan; scan++ )
+ {
+ SurfaceBlitCharacter( font, *scan, &dPoint, 255, 255, 255, 1 );
+ }
+
+ sprintf( bestInfo, "%s (%d points)", best.name, best.value );
+
+ font = GetFont(widescreen ? picFont : picHiScoreFont);
+ dPoint.v = widescreen? 388: 410;
+ dPoint.h = 320 - (GetTextWidth( font, bestInfo ) / 2);
+
+ for( scan = bestInfo; *scan; scan++ )
+ {
+ SurfaceBlitCharacter( font, *scan, &dPoint, 255, 255, 255, 1 );
+ }
+
+ SDLU_ReleaseSurface( backdropSurface );
+
+ memcpy( grid[0], best.grid, kGridAcross * kGridDown );
+ ResolveSuction( 0 );
+ RedrawBoardContents( 0 );
+ RefreshAll( );
+
+ nextA[0] = best.a;
+ nextB[0] = best.b;
+ nextG[0] = best.g;
+ nextM[0] = best.m;
+ RetrieveBlobs( 0 );
+
+ EraseSpriteBlobs( 0 );
+ blobX[0] = best.x;
+ blobR[0] = best.r;
+ DrawSpriteBlobs( 0, kNoSuction );
+
+ QuickFadeIn( NULL );
+ blobTime[0] = animTime[0] = GameTickCount( );
+
+ autoPattern = hiScorePattern;
+ tutorialTime = 0;
+}
+
+void AddHiscore( int score )
+{
+ short count, item;
+ char rank[50];
+ char text[256];
+ const char *playerName = "You";
+ const char *twoPlayerNames[] = { "Player 1", "Player 2" };
+ int highScoreLevel = -1;
+
+
+ // Check for high score
+ // (only do high scores if it's player vs CPU)
+
+ if( players == 1 &&
+ control[0] == kPlayerControl &&
+ control[1] == kAIControl )
+ {
+ for( count=0; count<=9; count++ )
+ {
+ if( score >= scores[count].score )
+ {
+ sprintf( rank, "%d points", score );
+ highScoreLevel = count;
+ break;
+ }
+ }
+ }
+
+ // Determine player's name for best combo
+
+ if( players == 2 ) playerName = twoPlayerNames[evenBetter.player];
+
+
+ // See if both best combo AND high score
+
+ if( evenBetter.value > best.value && highScoreLevel != -1 )
+ {
+
+ sprintf( text, "You got a high score and the best combo!" );
+
+ highScoreText = text;
+ highScoreRank = rank;
+
+ HandleDialog( kHiScoreDialog );
+
+ if( !finished )
+ {
+ highScoreName[kNameLength] = '\0';
+
+ memcpy( &best, &evenBetter, sizeof(Combo) );
+ strcpy( best.name, highScoreName );
+
+ for( item=8; item>=highScoreLevel; item-- )
+ {
+ memmove( &scores[item+1], &scores[item], sizeof( HighScore ) );
+ }
+
+ scores[highScoreLevel].score = score;
+ strcpy( scores[highScoreLevel].name, highScoreName );
+ }
+ }
+
+ // See if best combo has been won
+
+ else if( evenBetter.value > best.value )
+ {
+ sprintf( text, "Congratulations! %s got best combo!", playerName );
+
+ highScoreText = text;
+ highScoreRank = "";
+
+ HandleDialog( kHiScoreDialog );
+
+ if( !finished )
+ {
+ highScoreName[kNameLength] = '\0';
+
+ memcpy( &best, &evenBetter, sizeof(Combo) );
+ strcpy( best.name, highScoreName );
+ }
+ }
+
+ // See if high score has been won
+
+ else if( highScoreLevel != -1 )
+ {
+ highScoreText = "Congratulations! You got a high score!";
+ highScoreRank = rank;
+
+ HandleDialog( kHiScoreDialog );
+
+ if( !finished )
+ {
+ highScoreName[kNameLength] = '\0';
+
+ for( item=8; item>=highScoreLevel; item-- )
+ {
+ memmove( &scores[item+1], &scores[item], sizeof( HighScore ) );
+ }
+
+ scores[highScoreLevel].score = score;
+ strcpy( scores[highScoreLevel].name, highScoreName );
+ }
+ }
+}
--- a/src/hiscore.cpp
+++ /dev/null
@@ -1,501 +1,0 @@
-// hiscore.c
-
-#include "SDLU.h"
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <algorithm>
-
-#include "main.h"
-#include "gworld.h"
-#include "graphics.h"
-#include "score.h"
-#include "hiscore.h"
-#include "keyselect.h"
-#include "font.h"
-#include "blitter.h"
-#include "random.h"
-#include "pause.h"
-#include "level.h"
-#include "tutorial.h"
-#include "graymonitor.h"
-#include "players.h"
-#include "gameticks.h"
-#include "music.h"
-#include "soundfx.h"
-
-using std::min;
-
-Combo defaultBest =
-{
- /*bestGrid[kGridAcross][kGridDown] = */
- { { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty },
- { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty },
- { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, 1, 1, 1, 2, 2 },
- { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, 1, 1 },
- { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty },
- { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty } },
-
- /*bestA = */ 2,
- /*bestB = */ 2,
- /*bestM = */ false,
- /*bestG = */ false,
- /*bestLv = */ kTutorialLevel,
- /*bestX = */ 1,
- /*bestR = */ upRotate,
- /*bestPlayer = */ 0,
- /*bestValue = */ (40*1) + (50*9),
- /*bestName = */ "Tutorial"
-};
-
-Combo best =
-{
- /*bestGrid[kGridAcross][kGridDown] = */
- { { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty },
- { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty },
- { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, 1, 1, 1, 2, 2 },
- { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, 1, 1 },
- { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty },
- { kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty } },
-
- /*bestA = */ 2,
- /*bestB = */ 2,
- /*bestM = */ false,
- /*bestG = */ false,
- /*bestLv = */ kTutorialLevel,
- /*bestX = */ 1,
- /*bestR = */ upRotate,
- /*bestPlayer = */ 0,
- /*bestValue = */ (40*1) + (50*9),
- /*bestName = */ "Tutorial"
-};
-
-Combo evenBetter = {0};
-Combo potentialCombo[2];
-
-AutoPattern hiScorePattern[] =
-{
- { kIdleTicks, 60, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kBlockUntilComplete, 0, 0, NULL },
- { kIdleTicks, 60, 0, NULL },
- { kComplete, 0, 0, NULL }
-};
-
-HighScore scores[10] =
-{
- {"Leviathan", 40000},
- {"Dr. Crisis", 36000},
- {"Angel", 32000},
- {"Spike", 28000},
- {"Fox", 24000},
- {"Raguel", 20000},
- {"Kumo", 16000},
- {"Patty", 12000},
- {"Yuurei", 8000},
- {"Glurp", 4000}
-};
-
-HighScore defaultScores[10] =
-{
- {"Leviathan", 40000},
- {"Dr. Crisis", 36000},
- {"Angel", 32000},
- {"Spike", 28000},
- {"Fox", 24000},
- {"Raguel", 20000},
- {"Kumo", 16000},
- {"Patty", 12000},
- {"Yuurei", 8000},
- {"Glurp", 4000}
-};
-
-char highScoreName[256];
-const char *highScoreText;
-const char *highScoreRank;
-
-static void FadeScreen( SDL_Surface* hiScoreSurface, SDL_Surface* fadeSurface, int start, int end )
-{
- MTicks timer;
- int skip, frame, fade, color, direction, fadeStart, fadeEnd;
- SDL_Rect destSDLRect;
- SDL_Rect fullSDLRect = { 0, 0, 640, 480 };
- int black;
-
- black = SDL_MapRGB( fadeSurface->format, 0, 0, 0 );
-
- if( start < end )
- {
- direction = 1;
- fadeStart = 0;
- fadeEnd = 32;
- }
- else
- {
- direction = -1;
- fadeStart = 32;
- fadeEnd = 0;
- }
-
- skip = 1;
- timer = MTickCount( ) + 1;
- while( timer > MTickCount() ) { }
-
- for( frame = start; (direction>0)? (frame <= end): (frame >= end); frame += direction )
- {
- MRect drawRect = {0, 0, 15, 640};
- timer += skip;
-
- for( fade = fadeStart; fade != fadeEnd; fade += direction )
- {
- color = frame + fade;
- if( color < 0 ) color = 0;
- if( color > 31 ) color = 31;
-
- SDLU_MRectToSDLRect( &drawRect, &destSDLRect );
-
- switch( color )
- {
- case 0:
- SDLU_BlitSurface( hiScoreSurface, &destSDLRect,
- fadeSurface, &destSDLRect );
- break;
-
- case 31:
- SDL_FillRect( fadeSurface, &destSDLRect, black );
- break;
-
- default:
- SurfaceBlitColorOver( hiScoreSurface, fadeSurface,
- &drawRect, &drawRect,
- 0, 0, 0, _5TO8(color) );
- break;
- }
-
- OffsetMRect( &drawRect, 0, 15 );
- }
-
- SDLU_BlitFrontSurface( fadeSurface, &fullSDLRect, &fullSDLRect );
- SDLU_Present();
-
- if( timer <= MTickCount( ) )
- {
- skip = 2;
- }
- else
- {
- skip = 1;
- while( timer > MTickCount( ) )
- {
- SDLU_Yield();
- }
- }
- }
-}
-
-void ShowHiscore( void )
-{
- short count, length;
- char myString[256];
- int stringLength;
- SDL_Surface* hiScoreSurface;
- SDL_Surface* fadeSurface;
- SDL_Rect fullSDLRect = { 0, 0, 640, 480 };
- SkittlesFontPtr font;
- SDL_Color anyColor;
- MPoint dPoint;
- const char* highScores = "HIGH SCORES";
- int r, g, b;
-
- if (DeleteKeyIsPressed())
- {
- // If the user holds delete while opening the high scores,
- // clear the high score table.
-
- memcpy( &scores, &defaultScores, sizeof( scores ) );
- memcpy( &best, &defaultBest, sizeof( best ) );
- }
-
- hiScoreSurface = LoadPICTAsSurface( picBackdrop + (100 * RandomBefore(kLevels)), 32 );
- fadeSurface = SDLU_InitSurface( &fullSDLRect, 32 );
-
-
- SDLU_AcquireSurface( hiScoreSurface );
-
- SDLU_GetPixel( hiScoreSurface, RandomBefore( fullSDLRect.w ), RandomBefore( fullSDLRect.h ), &anyColor );
-
- anyColor.r = min( 255, anyColor.r + 112 );
- anyColor.g = min( 255, anyColor.g + 112 );
- anyColor.b = min( 255, anyColor.b + 112 );
-
- dPoint.v = widescreen? 100: 20;
- dPoint.h = 225;
- font = GetFont( picHiScoreFont );
- for( count=0; highScores[count]; count++ )
- {
- SurfaceBlitCharacter( font, highScores[count], &dPoint, 255, 255, 255, 1 );
- }
-
- font = GetFont(widescreen ? picFont : picHiScoreFont);
- for( count=0; count<=9; count++ )
- {
- r = ((255 * (10-count)) + (anyColor.r * count)) / 10;
- g = ((255 * (10-count)) + (anyColor.g * count)) / 10;
- b = ((255 * (10-count)) + (anyColor.b * count)) / 10;
-
- if (widescreen)
- dPoint.v = 150 + count * 24;
- else
- dPoint.v = 75 + count * 38;
- dPoint.h = 85;
-
- if( count<9 )
- {
- SurfaceBlitCharacter( font, count + '1', &dPoint, r, g, b, 1 );
- }
- else
- {
- SurfaceBlitCharacter( font, '1', &dPoint, r, g, b, 1 );
- SurfaceBlitCharacter( font, '0', &dPoint, r, g, b, 1 );
- }
-
- SurfaceBlitCharacter( font, '.', &dPoint, r, g, b, 1 );
- SurfaceBlitCharacter( font, ' ', &dPoint, r, g, b, 1 );
-
- length = 0;
- while( scores[count].name[length] && dPoint.h < 430 )
- {
- SurfaceBlitCharacter( font, scores[count].name[length++], &dPoint, r, g, b, 1 );
- }
-
- while( dPoint.h < 450 )
- {
- SurfaceBlitCharacter( font, '.', &dPoint, r, g, b, 1 );
- }
-
- dPoint.h = 470;
-
- stringLength = sprintf( myString, "%d", scores[count].score );
- for( length=0; length < stringLength; length++ )
- {
- SurfaceBlitCharacter( font, myString[length], &dPoint, r, g, b, 1 );
- }
- }
-
- SDLU_ReleaseSurface( hiScoreSurface );
-
- SDL_FillRect( g_frontSurface, &g_frontSurface->clip_rect, SDL_MapRGB( g_frontSurface->format, 0, 0, 0 ));
- SDLU_Present();
-
- SDLU_SetBrightness( 1.0f );
-
- FadeScreen( hiScoreSurface, fadeSurface, 31, -32 );
- do
- {
- }
- while( !AnyKeyIsPressed( ) && !SDLU_Button() );
- FadeScreen( hiScoreSurface, fadeSurface, -31, 32 );
-
- SDLU_SetBrightness( 0.0f );
-
- SDL_FreeSurface( hiScoreSurface );
- SDL_FreeSurface( fadeSurface );
-}
-
-void InitPotentialCombos( void )
-{
- memset( &potentialCombo[0], 0, sizeof(Combo) );
- memset( &potentialCombo[1], 0, sizeof(Combo) );
- potentialCombo[0].player = 0;
- potentialCombo[1].player = 1;
-}
-
-void SubmitCombo( Combo *in )
-{
- if( in->value > best.value && in->value > evenBetter.value )
- {
- PlayMono( kContinueSnd );
- memcpy( &evenBetter, in, sizeof( Combo ) );
- }
-}
-
-// Please note: This function may well be the biggest kludge in Candy Crisis.
-// It relies on tons of insider knowledge. But it works.
-void ShowBestCombo( void )
-{
- SkittlesFontPtr font;
- const char *bestCombo = "BEST COMBO";
- const char *scan;
- char bestInfo[256];
- MPoint dPoint;
- int levelCap;
-
- StopBalloon( );
- InitGame( kAutoControl, kNobodyControl );
- scoreWindowVisible[0] = false;
- grayMonitorVisible[0] = false;
-
- level = best.lv;
- levelCap = kLevels;
- if( (level < 1 || level > levelCap) && level != kTutorialLevel )
- {
- memcpy( &best, &defaultBest, sizeof(best) );
- showStartMenu = true;
- return;
- }
-
- BeginRound( false );
- character[0].dropSpeed = 12;
-
- SDLU_AcquireSurface( backdropSurface );
-
- font = GetFont(picHiScoreFont);
- dPoint.v = widescreen? 70: 40;
- dPoint.h = 225;
- for( scan = bestCombo; *scan; scan++ )
- {
- SurfaceBlitCharacter( font, *scan, &dPoint, 255, 255, 255, 1 );
- }
-
- sprintf( bestInfo, "%s (%d points)", best.name, best.value );
-
- font = GetFont(widescreen ? picFont : picHiScoreFont);
- dPoint.v = widescreen? 388: 410;
- dPoint.h = 320 - (GetTextWidth( font, bestInfo ) / 2);
-
- for( scan = bestInfo; *scan; scan++ )
- {
- SurfaceBlitCharacter( font, *scan, &dPoint, 255, 255, 255, 1 );
- }
-
- SDLU_ReleaseSurface( backdropSurface );
-
- memcpy( grid[0], best.grid, kGridAcross * kGridDown );
- ResolveSuction( 0 );
- RedrawBoardContents( 0 );
- RefreshAll( );
-
- nextA[0] = best.a;
- nextB[0] = best.b;
- nextG[0] = best.g;
- nextM[0] = best.m;
- RetrieveBlobs( 0 );
-
- EraseSpriteBlobs( 0 );
- blobX[0] = best.x;
- blobR[0] = best.r;
- DrawSpriteBlobs( 0, kNoSuction );
-
- QuickFadeIn( NULL );
- blobTime[0] = animTime[0] = GameTickCount( );
-
- autoPattern = hiScorePattern;
- tutorialTime = 0;
-}
-
-void AddHiscore( int score )
-{
- short count, item;
- char rank[50];
- char text[256];
- const char *playerName = "You";
- const char *twoPlayerNames[] = { "Player 1", "Player 2" };
- int highScoreLevel = -1;
-
-
- // Check for high score
- // (only do high scores if it's player vs CPU)
-
- if( players == 1 &&
- control[0] == kPlayerControl &&
- control[1] == kAIControl )
- {
- for( count=0; count<=9; count++ )
- {
- if( score >= scores[count].score )
- {
- sprintf( rank, "%d points", score );
- highScoreLevel = count;
- break;
- }
- }
- }
-
- // Determine player's name for best combo
-
- if( players == 2 ) playerName = twoPlayerNames[evenBetter.player];
-
-
- // See if both best combo AND high score
-
- if( evenBetter.value > best.value && highScoreLevel != -1 )
- {
-
- sprintf( text, "You got a high score and the best combo!" );
-
- highScoreText = text;
- highScoreRank = rank;
-
- HandleDialog( kHiScoreDialog );
-
- if( !finished )
- {
- highScoreName[kNameLength] = '\0';
-
- memcpy( &best, &evenBetter, sizeof(Combo) );
- strcpy( best.name, highScoreName );
-
- for( item=8; item>=highScoreLevel; item-- )
- {
- memmove( &scores[item+1], &scores[item], sizeof( HighScore ) );
- }
-
- scores[highScoreLevel].score = score;
- strcpy( scores[highScoreLevel].name, highScoreName );
- }
- }
-
- // See if best combo has been won
-
- else if( evenBetter.value > best.value )
- {
- sprintf( text, "Congratulations! %s got best combo!", playerName );
-
- highScoreText = text;
- highScoreRank = "";
-
- HandleDialog( kHiScoreDialog );
-
- if( !finished )
- {
- highScoreName[kNameLength] = '\0';
-
- memcpy( &best, &evenBetter, sizeof(Combo) );
- strcpy( best.name, highScoreName );
- }
- }
-
- // See if high score has been won
-
- else if( highScoreLevel != -1 )
- {
- highScoreText = "Congratulations! You got a high score!";
- highScoreRank = rank;
-
- HandleDialog( kHiScoreDialog );
-
- if( !finished )
- {
- highScoreName[kNameLength] = '\0';
-
- for( item=8; item>=highScoreLevel; item-- )
- {
- memmove( &scores[item+1], &scores[item], sizeof( HighScore ) );
- }
-
- scores[highScoreLevel].score = score;
- strcpy( scores[highScoreLevel].name, highScoreName );
- }
- }
-}
--- /dev/null
+++ b/src/keyselect.c
@@ -1,0 +1,65 @@
+// keyselect.c
+
+#include "SDLU.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "main.h"
+#include "players.h"
+#include "keyselect.h"
+
+
+SDL_Keycode playerKeys[2][4] =
+{
+ { SDLK_a, SDLK_d, SDLK_x, SDLK_s },
+ { SDLK_LEFT, SDLK_RIGHT, SDLK_DOWN, SDLK_UP }
+};
+
+const SDL_Keycode defaultPlayerKeys[2][4] =
+{
+ { SDLK_a, SDLK_d, SDLK_x, SDLK_s },
+ { SDLK_LEFT, SDLK_RIGHT, SDLK_DOWN, SDLK_UP }
+};
+
+
+void CheckKeys()
+{
+ int player;
+ int arraySize;
+ const Uint8* pressedKeys;
+
+ SDLU_PumpEvents();
+ pressedKeys = SDL_GetKeyboardState( &arraySize );
+
+ // Check for game keys
+ for( player = 0; player < 2; player++ )
+ {
+ if (pressedKeys[SDL_GetScancodeFromKey(playerKeys[player][0])])
+ hitKey[player].left++;
+ else
+ hitKey[player].left = 0;
+
+
+ if (pressedKeys[SDL_GetScancodeFromKey(playerKeys[player][1])])
+ hitKey[player].right++;
+ else
+ hitKey[player].right = 0;
+
+
+ if (pressedKeys[SDL_GetScancodeFromKey(playerKeys[player][2])])
+ hitKey[player].drop++;
+ else
+ hitKey[player].drop = 0;
+
+
+ if (pressedKeys[SDL_GetScancodeFromKey(playerKeys[player][3])])
+ hitKey[player].rotate++;
+ else
+ hitKey[player].rotate = 0;
+ }
+
+ pauseKey = pressedKeys[SDL_SCANCODE_ESCAPE];
+}
--- a/src/keyselect.cpp
+++ /dev/null
@@ -1,65 +1,0 @@
-// keyselect.c
-
-#include "SDLU.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "main.h"
-#include "players.h"
-#include "keyselect.h"
-
-
-SDL_Keycode playerKeys[2][4] =
-{
- { SDLK_a, SDLK_d, SDLK_x, SDLK_s },
- { SDLK_LEFT, SDLK_RIGHT, SDLK_DOWN, SDLK_UP }
-};
-
-const SDL_Keycode defaultPlayerKeys[2][4] =
-{
- { SDLK_a, SDLK_d, SDLK_x, SDLK_s },
- { SDLK_LEFT, SDLK_RIGHT, SDLK_DOWN, SDLK_UP }
-};
-
-
-void CheckKeys()
-{
- int player;
- int arraySize;
- const Uint8* pressedKeys;
-
- SDLU_PumpEvents();
- pressedKeys = SDL_GetKeyboardState( &arraySize );
-
- // Check for game keys
- for( player = 0; player < 2; player++ )
- {
- if (pressedKeys[SDL_GetScancodeFromKey(playerKeys[player][0])])
- hitKey[player].left++;
- else
- hitKey[player].left = 0;
-
-
- if (pressedKeys[SDL_GetScancodeFromKey(playerKeys[player][1])])
- hitKey[player].right++;
- else
- hitKey[player].right = 0;
-
-
- if (pressedKeys[SDL_GetScancodeFromKey(playerKeys[player][2])])
- hitKey[player].drop++;
- else
- hitKey[player].drop = 0;
-
-
- if (pressedKeys[SDL_GetScancodeFromKey(playerKeys[player][3])])
- hitKey[player].rotate++;
- else
- hitKey[player].rotate = 0;
- }
-
- pauseKey = pressedKeys[SDL_SCANCODE_ESCAPE];
-}
--- /dev/null
+++ b/src/level.c
@@ -1,0 +1,1435 @@
+// level.c
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "SDLU.h"
+
+#include "main.h"
+#include "level.h"
+#include "score.h"
+#include "random.h"
+#include "grays.h"
+#include "gameticks.h"
+#include "players.h"
+#include "graymonitor.h"
+#include "opponent.h"
+#include "gworld.h"
+#include "graphics.h"
+#include "music.h"
+#include "control.h"
+#include "tweak.h"
+#include "soundfx.h"
+#include "next.h"
+#include "hiscore.h"
+#include "victory.h"
+#include "blitter.h"
+#include "zap.h"
+#include "keyselect.h"
+#include "tutorial.h"
+#include "pause.h"
+
+MRect stageWindowZRect, stageWindowRect;
+Character character[2];
+int level, players, credits, difficulty[2] = {kHardLevel, kHardLevel};
+int difficultyTicks, backdropTicks, backdropFrame;
+
+#define kNumSplats 16
+#define kIdleSplat -2
+#define kFallingSplat -1
+#define kTitleItems 8
+#define kIncrementPerFrame 2
+#define kSplatType 4
+
+const int startSkip = 1;
+static MBoolean shouldFullRepaint = false;
+static MTicks startMenuTime = 0;
+static int splatState[kNumSplats], splatColor[kNumSplats], splatSide[kNumSplats];
+static MRect splatBlob[kNumSplats];
+
+enum
+{
+ kTitleItemTutorial,
+ kTitleItem1PGame,
+ kTitleItem2PGame,
+ kTitleItemSolitaire,
+ kTitleItemHighScores,
+ kTitleItemControls,
+ kTitleItemCredits,
+ kTitleItemQuit,
+};
+
+typedef struct TitleItemDef
+{
+ const char* name;
+ MRGBColor color1;
+ MRGBColor color2;
+ MRect rect;
+} TitleItemDef;
+
+static const TitleItemDef k_titleItemDefs[kTitleItems] =
+{
+ { "\x03 Tutorial Mode", {204, 67,137}, {101, 74,207}, {155, 203, 207, 426} },
+ { "\x03 One Player Game", { 35, 31,240}, { 81,237,252}, {225, 179, 281, 451} },
+ { "\x03 Two Player Game", {212,194, 48}, {255,196, 56}, {297, 182, 352, 454} },
+ { "\x03 Solitaire Crisis", {102,247,106}, {125,237,179}, {358, 183, 428, 458} },
+ { "\x03 High Scores", {234,244,132}, {192,218, 85}, {429, 280, 478, 390} },
+ { "\x03 Controls", { 64, 88,212}, { 62, 87,205}, {430, 187, 479, 280} },
+ { "\x03 Credits", {245, 7, 78}, {254,128,156}, { 6, 370, 59, 423} },
+ { "\x03 Quit", {107,105,106}, {169,167,168}, {433, 390, 477, 446} }
+};
+
+const int kCursorWidth = 32;
+const int kCursorHeight = 32;
+
+#if USE_CURSOR_SPRITE
+static void InsertCursor( MPoint mouseHere, SDL_Surface* scratch, SDL_Surface* surface )
+{
+ SkittlesFontPtr cursorFont = GetFont( picFont );
+ SDL_Rect cursorBackSDLRect = { 0, 0, kCursorWidth, kCursorHeight };
+ SDL_Rect cursorFrontSDLRect = { 0, 0, kCursorWidth, kCursorHeight };
+ MPoint mouseHereToo = mouseHere;
+
+ cursorFrontSDLRect.x = mouseHere.h;
+ cursorFrontSDLRect.y = mouseHere.v;
+
+ SDLU_BlitSurface( surface, &cursorFrontSDLRect,
+ scratch, &cursorBackSDLRect );
+
+ SDLU_AcquireSurface( surface );
+ SurfaceBlitCharacter( cursorFont, '\x05', &mouseHere, 0, 0, 0, 0 );
+ SurfaceBlitCharacter( cursorFont, '\x04', &mouseHereToo, 255, 255, 255, 0 );
+ SDLU_ReleaseSurface( surface );
+}
+
+static void RemoveCursor( MPoint mouseHere, SDL_Surface* scratch, SDL_Surface* surface )
+{
+ SDL_Rect cursorBackSDLRect = { 0, 0, kCursorWidth, kCursorHeight };
+ SDL_Rect cursorFrontSDLRect = { 0, 0, kCursorWidth, kCursorHeight };
+
+ cursorFrontSDLRect.x = mouseHere.h;
+ cursorFrontSDLRect.y = mouseHere.v;
+
+ SDLU_BlitSurface( scratch, &cursorBackSDLRect,
+ surface, &cursorFrontSDLRect );
+}
+#endif
+
+static void GameStartMenuRepaint()
+{
+ shouldFullRepaint = true;
+}
+
+void GameStartMenu( void )
+{
+ MBoolean useNewTitle = widescreen;
+
+ // NOTE: be wary of initializing variables here! This function can run top-to-bottom
+ // multiple times in a row, thanks to "redo". Put initializations after redo.
+ SDL_Surface* gameStartSurface;
+ SDL_Surface* gameStartDrawSurface;
+#if USE_CURSOR_SPRITE
+ SDL_Surface* cursorBackSurface;
+#endif
+ SDL_Rect backdropSDLRect = { 0, 0, 640, 480 };
+ SDL_Rect cursorBackSDLRect = { 0, 0, kCursorWidth, kCursorHeight };
+ SDL_Rect destSDLRect;
+ MRect drawRect[4], chunkRect, tempRect;
+ int blob, count, oldGlow, splat, chunkType, selected;
+ int skip;
+ MPoint mouse;
+ MPoint dPoint;
+ unsigned int black;
+ int combo[2], comboBright[2], missBright[2];
+ SkittlesFontPtr smallFont = GetFont( picFont );
+ SkittlesFontPtr tinyFont = GetFont( picTinyFont );
+ SDL_Rect meterRect[2] = { { 30, 360, 110, 20 }, { 530, 360, 110, 20 } };
+ TitleItemDef titleItems[kTitleItems];
+ int titleGlow[kTitleItems];
+ int shouldAddBlob;
+ const int kTitleGlowOff = useNewTitle? 150: 192;
+ const bool secretCreditsItem = !useNewTitle;
+
+ const int kLeftSide = 0, kRightSide = 1, kGlow = 2, kCursor = 3;
+
+
+redo:
+ memcpy(titleItems, k_titleItemDefs, sizeof(titleItems));
+
+ combo[0] = combo[1] = 0;
+ comboBright[0] = comboBright[1] = 0;
+ missBright[0] = missBright[1] = 0;
+
+ skip = 1;
+ selected = -1;
+ mouse.h = mouse.v = 0;
+
+ if( finished ) return;
+
+ if( musicSelection != 13 ) ChooseMusic( 13 );
+
+ for( count=0; count<kTitleItems; count++ )
+ {
+ titleGlow[count] = kTitleGlowOff;
+ }
+
+ if (secretCreditsItem)
+ {
+ titleGlow[kTitleItemCredits] = 0;
+ }
+
+ for( count=0; count<kNumSplats; count++ )
+ {
+ splatState[count] = kIdleSplat;
+ }
+
+ // make background surface
+ gameStartSurface = LoadPICTAsSurface( picGameStart, 32 );
+ black = SDL_MapRGB( gameStartSurface->format, 0, 0, 0 );
+
+ // make cursor backing store
+#if USE_CURSOR_SPRITE
+ cursorBackSurface = SDLU_InitSurface( &cursorBackSDLRect, 32 );
+ SDL_FillRect( cursorBackSurface, &cursorBackSDLRect, black );
+#endif
+
+ // make drawing surface
+ gameStartDrawSurface = SDLU_InitSurface( &backdropSDLRect, 32 );
+ if (!useNewTitle)
+ {
+ SDLU_BlitSurface(gameStartSurface, &gameStartSurface->clip_rect,
+ gameStartDrawSurface, &gameStartDrawSurface->clip_rect);
+ }
+ else
+ {
+ // Prepare new title screen
+ SDL_FillRect(gameStartDrawSurface, &gameStartDrawSurface->clip_rect, black);
+
+ // Copy logo from original title screen to where we want it
+ SDL_Rect r1 = {0, 0, 640, 150};
+ SDL_Rect r2 = {0, 70, 640, 150};
+ SDLU_BlitSurface(gameStartSurface, &r1, gameStartDrawSurface, &r2);
+
+ // Now we're going to draw title items on gameStartSurface
+ SDL_FillRect(gameStartSurface, &gameStartSurface->clip_rect, black);
+ SDLU_AcquireSurface(gameStartSurface);
+
+ SkittlesFontPtr font = GetFont(picFont);
+ int left = 225;
+ dPoint.h = left;
+ dPoint.v = 215;
+ for (int i = 0; i < kTitleItems; i++)
+ {
+ TitleItemDef* item = &titleItems[i];
+ item->rect.left = dPoint.h;
+ item->rect.top = dPoint.v - 6;
+ item->rect.bottom = dPoint.v + 16 + 6;
+ int nameLength = (int) strlen(item->name);
+ for (int charNo = 0; charNo < nameLength; charNo++)
+ {
+ char c = item->name[charNo];
+ float p = charNo / (float) (nameLength - 1);
+ int red = item->color1.red * (1.0f - p) + item->color2.red * p;
+ int green = item->color1.green * (1.0f - p) + item->color2.green * p;
+ int blue = item->color1.blue * (1.0f - p) + item->color2.blue * p;
+ SurfaceBlitCharacter(font, c, &dPoint, red, green, blue, 1);
+ }
+ item->rect.right = dPoint.h;
+ dPoint.h = left;
+ dPoint.v += 24;
+ }
+ SDLU_ReleaseSurface(gameStartSurface);
+ }
+
+ // darken menu items
+ for( count=0; count<kTitleItems; count++ )
+ {
+ SurfaceBlitColorOver( gameStartSurface, gameStartDrawSurface,
+ &titleItems[count].rect, &titleItems[count].rect,
+ 0, 0, 0, titleGlow[count] );
+ }
+
+ SDLU_BlitFrontSurface( gameStartDrawSurface, &backdropSDLRect, &backdropSDLRect );
+ SDLU_Present();
+
+ WaitForRelease();
+
+ QuickFadeIn( NULL );
+
+ DoFullRepaint = GameStartMenuRepaint;
+
+ shouldAddBlob = 5;
+ startMenuTime = MTickCount( );
+ while( ( selected == -1 || !SDLU_Button() ) && !finished )
+ {
+ startMenuTime += skip;
+
+ UpdateSound();
+
+ // Add a new falling blob
+ --shouldAddBlob;
+ if (shouldAddBlob <= 0)
+ {
+ for( blob=0; blob<kNumSplats; blob++ )
+ {
+ if( splatState[blob] == kIdleSplat )
+ {
+ splatSide[blob] = RandomBefore(2);
+ splatBlob[blob].top = -24 - RandomBefore(15);
+ splatBlob[blob].left = (splatSide[blob] == 0)? RandomBefore( 110 ): 640 - kBlobHorizSize - RandomBefore( 110 );
+ splatBlob[blob].bottom = splatBlob[blob].top + kBlobVertSize;
+ splatBlob[blob].right = splatBlob[blob].left + kBlobHorizSize;
+ splatColor[blob] = ((startMenuTime >> 2) % kBlobTypes) + 1;
+ splatState[blob] = kFallingSplat;
+
+ break;
+ }
+ }
+ shouldAddBlob = 5;
+ }
+
+ // Erase and redraw falling blobs and chunks
+
+ SDLU_AcquireSurface( gameStartDrawSurface );
+
+ // Take the cursor out of the scene
+#if USE_CURSOR_SPRITE
+ RemoveCursor( mouse, cursorBackSurface, gameStartDrawSurface );
+ drawRect[kCursor].top = mouse.v;
+ drawRect[kCursor].left = mouse.h;
+ drawRect[kCursor].bottom = mouse.v + kCursorHeight;
+ drawRect[kCursor].right = mouse.h + kCursorWidth;
+#endif
+
+ // Inverted rectangles mean "nothing to do."
+ drawRect[kLeftSide].top = drawRect[kRightSide].top = drawRect[kGlow].top =
+ drawRect[kLeftSide].left = drawRect[kRightSide].left = drawRect[kGlow].left = 9999;
+ drawRect[kLeftSide].bottom = drawRect[kRightSide].bottom = drawRect[kGlow].bottom =
+ drawRect[kLeftSide].right = drawRect[kRightSide].right = drawRect[kGlow].right = -9999;
+
+ // Get cursor position
+ SDLU_GetMouse( &mouse );
+ if( mouse.v > (widescreen ? 400 : 460) )
+ mouse.v = (widescreen ? 400 : 460);
+
+ // Erase falling blobs
+ for( blob=0; blob<kNumSplats; blob++ )
+ {
+ if( splatState[blob] == kFallingSplat )
+ {
+ SDL_FillRect( gameStartDrawSurface, SDLU_MRectToSDLRect( &splatBlob[blob], &destSDLRect ), black );
+ UnionMRect( &drawRect[splatSide[blob]], &splatBlob[blob], &drawRect[splatSide[blob]] );
+
+ OffsetMRect( &splatBlob[blob], 0, startSkip * (6 + (splatBlob[blob].bottom / 20)) );
+ }
+ else if( splatState[blob] >= kIncrementPerFrame )
+ {
+ for( splat=-3; splat<=3; splat++ )
+ {
+ if( splat )
+ {
+ chunkRect = splatBlob[blob];
+ GetZapStyle( 0, &chunkRect, &splatColor[blob], &chunkType, splat, splatState[blob]-kIncrementPerFrame, kSplatType );
+ SDL_FillRect( gameStartDrawSurface, SDLU_MRectToSDLRect( &chunkRect, &destSDLRect ), black );
+ UnionMRect( &drawRect[splatSide[blob]], &chunkRect, &drawRect[splatSide[blob]] );
+ }
+ }
+
+ SDL_FillRect( gameStartDrawSurface, SDLU_MRectToSDLRect( &splatBlob[blob], &destSDLRect ), black );
+ UnionMRect( &drawRect[splatSide[blob]], &splatBlob[blob], &drawRect[splatSide[blob]] );
+ }
+ }
+
+ // Draw combo meters
+
+ for( count=0; count<2; count++ )
+ {
+ int bright = comboBright[count];
+ int mBright = missBright[count];
+ if( bright || mBright )
+ {
+ SDL_FillRect( gameStartDrawSurface, &meterRect[count], black );
+ UnionMRect( &drawRect[count], SDLU_SDLRectToMRect( &meterRect[count], &tempRect ), &drawRect[count] );
+
+ if( mBright > 1 )
+ {
+ dPoint.v = meterRect[count].y;
+ dPoint.h = meterRect[count].x + 10;
+ SurfaceBlitCharacter( smallFont, 'M', &dPoint, mBright, mBright >> 2, mBright >> 2, 1 );
+ SurfaceBlitCharacter( smallFont, 'I', &dPoint, mBright, mBright >> 2, mBright >> 2, 1 );
+ SurfaceBlitCharacter( smallFont, 'S', &dPoint, mBright, mBright >> 2, mBright >> 2, 1 );
+ SurfaceBlitCharacter( smallFont, 'S', &dPoint, mBright, mBright >> 2, mBright >> 2, 1 );
+ missBright[count] -= 8;
+ }
+ else if( (combo[count] >= 10) && (bright > 1) )
+ {
+ char number[16] = { 0 };
+ char* scan;
+ sprintf( number, "%d", combo[count] );
+
+ dPoint.v = meterRect[count].y + 3;
+ dPoint.h = meterRect[count].x;
+
+ SurfaceBlitCharacter( tinyFont, 'C', &dPoint, bright, bright, bright, 1 );
+ SurfaceBlitCharacter( tinyFont, 'O', &dPoint, bright, bright, bright, 1 );
+ SurfaceBlitCharacter( tinyFont, 'M', &dPoint, bright, bright, bright, 1 );
+ SurfaceBlitCharacter( tinyFont, 'B', &dPoint, bright, bright, bright, 1 );
+ SurfaceBlitCharacter( tinyFont, 'O', &dPoint, bright, bright, bright, 1 );
+ SurfaceBlitCharacter( tinyFont, ' ', &dPoint, bright, bright, bright, 1 );
+ dPoint.v -= 3;
+
+ for( scan = number; *scan; scan++ )
+ {
+ SurfaceBlitCharacter( smallFont, *scan, &dPoint, bright>>2, bright>>2, bright, 1 );
+ }
+
+ comboBright[count] -= 16;
+ }
+ else
+ {
+ comboBright[count] = 0;
+ }
+ }
+ }
+
+ // Redraw falling blobs
+ for( blob=0; blob<kNumSplats; blob++ )
+ {
+ if( splatState[blob] == kFallingSplat )
+ {
+ int bottom = widescreen? 420: 480;
+ if( splatBlob[blob].bottom >= bottom )
+ {
+ splatBlob[blob].top = bottom - kBlobVertSize;
+ splatBlob[blob].bottom = bottom;
+ splatState[blob] = 1;
+
+ // Process combos
+ if( mouse.v > bottom &&
+ mouse.h >= (splatBlob[blob].left - 30) &&
+ mouse.h <= (splatBlob[blob].right + 10) )
+ {
+ combo[splatSide[blob]]++;
+ comboBright[splatSide[blob]] = 255;
+ }
+ else
+ {
+ if( combo[splatSide[blob]] >= 10 ) missBright[splatSide[blob]] = 255;
+ combo[splatSide[blob]] = 0;
+ comboBright[splatSide[blob]] = 0;
+ }
+ }
+ else
+ {
+ SurfaceDrawSprite( &splatBlob[blob], splatColor[blob], kNoSuction );
+ UnionMRect( &drawRect[splatSide[blob]], &splatBlob[blob], &drawRect[splatSide[blob]] );
+ }
+ }
+
+ if( splatState[blob] >= 0 && splatState[blob] <= kZapFrames )
+ {
+ if( splatState[blob] <= (kZapFrames - kIncrementPerFrame) )
+ {
+ chunkType = 0;
+
+ for( splat=-3; splat<=3; splat++ )
+ {
+ if( splat )
+ {
+ chunkRect = splatBlob[blob];
+ GetZapStyle( 0, &chunkRect, &splatColor[blob], &chunkType, splat, splatState[blob], kSplatType );
+ SurfaceDrawSprite( &chunkRect, splatColor[blob], chunkType );
+ UnionMRect( &drawRect[splatSide[blob]], &chunkRect, &drawRect[splatSide[blob]] );
+ }
+ }
+
+ SurfaceDrawSprite( &splatBlob[blob], splatColor[blob], chunkType );
+ UnionMRect( &drawRect[splatSide[blob]], &splatBlob[blob], &drawRect[splatSide[blob]] );
+ }
+
+ splatState[blob] += kIncrementPerFrame;
+ if( splatState[blob] > kZapFrames ) splatState[blob] = kIdleSplat;
+ }
+ }
+
+ SDLU_ReleaseSurface( gameStartDrawSurface );
+
+ // Find mouse coords
+
+ selected = -1;
+ for( count=0; count<kTitleItems; count++ )
+ {
+ if( MPointInMRect( mouse, &titleItems[count].rect ) )
+ {
+ selected = count;
+ break;
+ }
+ }
+
+ if (secretCreditsItem)
+ {
+ titleGlow[kTitleItemCredits] = 0;
+ }
+
+ // update glows
+ for (int glowUpdate=0; glowUpdate < kTitleItems; ++glowUpdate)
+ {
+ const MRect* titleRect = &titleItems[glowUpdate].rect;
+ oldGlow = titleGlow[glowUpdate];
+
+ if( selected == glowUpdate )
+ {
+ titleGlow[glowUpdate] -= (6 * startSkip);
+ if( titleGlow[glowUpdate] < 0 ) titleGlow[glowUpdate] = 0;
+ }
+ else
+ {
+ titleGlow[glowUpdate] += (6 * startSkip);
+ if( titleGlow[glowUpdate] > kTitleGlowOff ) titleGlow[glowUpdate] = kTitleGlowOff;
+ }
+
+ if( titleGlow[glowUpdate] != oldGlow )
+ {
+ SurfaceBlitColorOver( gameStartSurface, gameStartDrawSurface,
+ titleRect, titleRect,
+ 0, 0, 0, titleGlow[glowUpdate] );
+
+ drawRect[kGlow].top = MinShort(drawRect[kGlow].top, titleRect->top);
+ drawRect[kGlow].left = MinShort(drawRect[kGlow].left, titleRect->left);
+ drawRect[kGlow].bottom = MaxShort(drawRect[kGlow].bottom, titleRect->bottom);
+ drawRect[kGlow].right = MaxShort(drawRect[kGlow].right, titleRect->right);
+ }
+ }
+
+ // Reinsert the cursor into the scene
+#if USE_CURSOR_SPRITE
+ InsertCursor( mouse, cursorBackSurface, gameStartDrawSurface );
+ drawRect[kCursor].top = min<short>( drawRect[kCursor].top, mouse.v );
+ drawRect[kCursor].left = min<short>( drawRect[kCursor].left, mouse.h );
+ drawRect[kCursor].bottom = max<short>( drawRect[kCursor].bottom, mouse.v + kCursorHeight );
+ drawRect[kCursor].right = max<short>( drawRect[kCursor].right, mouse.h + kCursorWidth );
+#endif
+ SDLU_SetSystemCursor( selected < 0 ? SYSTEM_CURSOR_ARROW : SYSTEM_CURSOR_HAND );
+
+ // Copy down everything
+ if( shouldFullRepaint )
+ {
+ SDLU_BlitFrontSurface( gameStartDrawSurface, &gameStartDrawSurface->clip_rect, &gameStartDrawSurface->clip_rect );
+ shouldFullRepaint = false;
+ }
+ else
+ {
+ for( count=0; count<4; count++ )
+ {
+ if( drawRect[count].left < drawRect[count].right )
+ {
+ SDLU_MRectToSDLRect( &drawRect[count], &destSDLRect );
+ SDLU_BlitFrontSurface( gameStartDrawSurface, &destSDLRect, &destSDLRect );
+ }
+ }
+ }
+
+ SDLU_Present();
+
+ // Skip frames? Or delay?
+ if( startMenuTime <= MTickCount( ) )
+ {
+ startMenuTime = MTickCount( );
+ skip = 2;
+ }
+ else
+ {
+ skip = 1;
+ while( startMenuTime > MTickCount( ) )
+ {
+ SDLU_Yield();
+ }
+ }
+ }
+
+ DoFullRepaint = NoPaint;
+
+ if( finished )
+ {
+ selected = kTitleItemQuit;
+ }
+ else
+ {
+ SDLU_SetSystemCursor( SYSTEM_CURSOR_OFF );
+ }
+
+ switch( selected )
+ {
+ case kTitleItemTutorial:
+ case kTitleItem1PGame:
+ case kTitleItem2PGame:
+ case kTitleItemSolitaire:
+ PlayMono( kChime );
+ break;
+ }
+
+ SDL_FreeSurface( gameStartSurface );
+ SDL_FreeSurface( gameStartDrawSurface );
+#if USE_CURSOR_SPRITE
+ SDL_FreeSurface( cursorBackSurface );
+#endif
+
+ QuickFadeOut( NULL );
+
+ switch( selected )
+ {
+ case kTitleItemTutorial:
+ InitGame( kAutoControl, kNobodyControl );
+ level = kTutorialLevel;
+ BeginRound( true );
+ InitTutorial( );
+ QuickFadeIn( NULL );
+ break;
+
+ case kTitleItem1PGame:
+ case kTitleItem2PGame:
+ case kTitleItemSolitaire:
+ {
+ int player2[] = { 0, kAIControl, kPlayerControl, kNobodyControl };
+
+ InitGame( kPlayerControl, player2[selected] );
+ BeginRound( true );
+ QuickFadeIn( NULL );
+ break;
+ }
+
+ case kTitleItemHighScores:
+ ShowHiscore();
+ ShowBestCombo();
+ break;
+
+ case kTitleItemControls:
+ {
+ int currentID = RandomBefore(kLevels) * 100;
+
+ DrawPICTInSurface( boardSurface[0], picBoard + currentID );
+ DrawPICTInSurface( g_frontSurface, picBackdrop + currentID );
+ SDLU_Present();
+
+ QuickFadeIn( NULL );
+ HandleDialog( kControlsDialog );
+ QuickFadeOut( NULL );
+ goto redo;
+ }
+
+ case kTitleItemCredits:
+ {
+ SharewareVictory();
+ goto redo;
+ }
+
+ case kTitleItemQuit:
+ finished = true;
+ break;
+ }
+}
+
+void ShowGameOverScreen( void )
+{
+ unsigned int timer = MTickCount() + (60*3);
+
+ QuickFadeOut(NULL);
+
+ DrawPICTInSurface( g_frontSurface, picGameOver );
+
+ SDL_Rect widescreenCropBackup = g_widescreenCrop;
+ g_widescreenCrop.y = 30;
+
+ SDLU_Present();
+
+ QuickFadeIn( NULL );
+ do
+ {
+ if( MTickCount() > timer ) break;
+ SDLU_Yield();
+ }
+ while( !AnyKeyIsPressed( ) && !SDLU_Button() );
+ QuickFadeOut( NULL );
+
+ g_widescreenCrop = widescreenCropBackup;
+}
+
+void InitStage( void )
+{
+ stageWindowZRect.top = stageWindowZRect.left = 0;
+ stageWindowZRect.bottom = 32; stageWindowZRect.right = 64;
+
+ stageWindowRect = stageWindowZRect;
+ CenterRectOnScreen( &stageWindowRect, 0.5, 0.65 );
+}
+
+void DrawStage( void )
+{
+ SDL_Surface* levelSurface;
+ SDL_Rect sourceSDLRect, destSDLRect;
+ MRect numberRect = { 0, kNumberHorizSize/8, kNumberVertSize, kNumberHorizSize*9/8 };
+
+ switch( players )
+ {
+ case 0:
+ case 2:
+ break;
+
+ case 1:
+ SDLU_MRectToSDLRect( &stageWindowZRect, &sourceSDLRect );
+ SDLU_MRectToSDLRect( &stageWindowRect, &destSDLRect );
+
+ levelSurface = SDLU_InitSurface( &sourceSDLRect, 32 );
+
+ SDLU_AcquireSurface( levelSurface );
+
+ SDLU_BlitSurface( boardSurface[0], &sourceSDLRect,
+ levelSurface, &sourceSDLRect );
+
+ if( level < 10 )
+ {
+ OffsetMRect( &numberRect, kNumberHorizSize*3/8, 0 );
+ }
+
+ DrawCharacter( kCharacterStage, &numberRect );
+ OffsetMRect( &numberRect, kNumberHorizSize, 0 );
+ DrawCharacter( kCharacterStage+1, &numberRect );
+
+ if( level < 10 )
+ {
+ OffsetMRect( &numberRect, kNumberHorizSize, 0 );
+ DrawCharacter( level + '0', &numberRect );
+ }
+ else
+ {
+ OffsetMRect( &numberRect, kNumberHorizSize*3/4, 0 );
+ DrawCharacter( (level / 10) + '0', &numberRect );
+ OffsetMRect( &numberRect, kNumberHorizSize, 0 );
+ DrawCharacter( (level % 10) + '0', &numberRect );
+ }
+
+ SDLU_BlitFrontSurface( levelSurface, &sourceSDLRect, &destSDLRect );
+
+ SDLU_ReleaseSurface( levelSurface );
+ SDL_FreeSurface( levelSurface );
+
+ break;
+ }
+}
+
+void InitGame( int player1, int player2 )
+{
+ playerWindowVisible[0] = true;
+ nextWindowVisible[0] = true;
+ scoreWindowVisible[0] = true;
+ grayMonitorVisible[0] = true;
+
+ if( player2 == kNobodyControl )
+ {
+ playerWindowVisible[1] = false;
+ nextWindowVisible[1] = false;
+ scoreWindowVisible[1] = false;
+ grayMonitorVisible[1] = false;
+
+ CenterRectOnScreen( &playerWindowRect[0], 0.5, 0.5 );
+ CenterRectOnScreen( &scoreWindowRect[0], 0.5, 0.89 );
+ CenterRectOnScreen( &grayMonitorRect[0], 0.5, 0.11 );
+ CenterRectOnScreen( &nextWindowRect[0], 0.3, 0.25 );
+
+ CenterRectOnScreen( &stageWindowRect, 0.3, 0.65 );
+ CenterRectOnScreen( &opponentWindowRect, 0.3, 0.5 );
+ }
+ else
+ {
+ playerWindowVisible[1] = true;
+ nextWindowVisible[1] = true;
+ scoreWindowVisible[1] = true;
+ grayMonitorVisible[1] = true;
+
+ CenterRectOnScreen( &playerWindowRect[0], kLeftPlayerWindowCenter, 0.5 );
+ CenterRectOnScreen( &scoreWindowRect[0], kLeftPlayerWindowCenter, 0.89 );
+ CenterRectOnScreen( &grayMonitorRect[0], kLeftPlayerWindowCenter, 0.11 );
+ CenterRectOnScreen( &nextWindowRect[0], 0.46, 0.25 );
+
+ CenterRectOnScreen( &playerWindowRect[1], kRightPlayerWindowCenter, 0.5 );
+ CenterRectOnScreen( &scoreWindowRect[1], kRightPlayerWindowCenter, 0.89 );
+ CenterRectOnScreen( &grayMonitorRect[1], kRightPlayerWindowCenter, 0.11 );
+ CenterRectOnScreen( &nextWindowRect[1], 0.54, 0.25 );
+
+ CenterRectOnScreen( &stageWindowRect, 0.5, 0.65 );
+ CenterRectOnScreen( &opponentWindowRect, 0.5, 0.5 );
+ }
+
+ // In widescreen mode, move score/gray windows closer to the playfield
+ // so they fit in the cropped screen.
+ ResetWidescreenLayout();
+
+ nextWindowVisible[0] = ( player1 == kAutoControl )? false: true;
+
+ players = (player1 == kPlayerControl) + (player2 == kPlayerControl);
+
+ if( players < 2 )
+ {
+ difficulty[0] = difficulty[1] = kHardLevel;
+ }
+
+ control[0] = player1;
+ control[1] = player2;
+
+ score[0] = score[1] = displayedScore[0] = displayedScore[1] = 0;
+ roundStartScore[0] = roundStartScore[1] = 0;
+
+ level = 1;
+ credits = (player2 == kNobodyControl)? 1: 5;
+}
+
+void ResetWidescreenLayout()
+{
+ int miniWindowOffset = widescreen ? 4 : 16;
+
+ for (int i = 0; i < 2; i++)
+ {
+ grayMonitorRect[i].top = playerWindowRect[i].top - 32 - miniWindowOffset;
+ grayMonitorRect[i].bottom = playerWindowRect[i].top - miniWindowOffset;
+ scoreWindowRect[i].top = playerWindowRect[i].bottom + miniWindowOffset;
+ scoreWindowRect[i].bottom = playerWindowRect[i].bottom + 16 + miniWindowOffset;
+ }
+}
+
+MBoolean InitCharacter( int player, int level )
+{
+ const Character characterList[] = {
+ { -1 }, // no zero'th character
+ { 0, 3, 1, { 8, 8, 8, 8, 8, 8 }, 13, 9, 0, 25, { 0, _15TO8_8_8(0), 0, 0, _15TO8_8_8(0), 0 }, true },
+ { 1, 6, 2, { 10, 9, 8, 8, 9, 10 }, 12, 7, 1, 20, { 0, _15TO8_8_8(223), 7, 0, _15TO8_8_8(0), 0 }, true },
+ { 2, 9, 3, { 7, 7, 7, 11, 7, 7 }, 10, 6, 2, 17, { 0, _15TO8_8_8(0), 0, 0, _15TO8_8_8(0), 0 }, false },
+ { 3, 12, 4, { 11, 10, 9, 8, 7, 6 }, 8, 5, 3, 13, { 0, _15TO8_8_8(32767), 4, 0, _15TO8_8_8(16912), 4 }, false },
+ { 4, 15, 0, { 5, 9, 10, 10, 9, 5 }, 7, 4, 4, 10, { 0, _15TO8_8_8(32767), 1, 0, _15TO8_8_8(0), 0 }, false },
+ { 5, 17, 1, { 4, 7, 11, 11, 6, 3 }, 7, 2, 5, 8, { 0, _15TO8_8_8(14835), 8, 0, _15TO8_8_8(0), 0 }, false },
+ { 6, 18, 2, { 7, 9, 10, 10, 9, 7 }, 6, 4, 6, 7, { 0, _15TO8_8_8(0), 0, 0, _15TO8_8_8(0), 0 }, false },
+ { 7, 20, 3, { 5, 10, 10, 10, 10, 5 }, 5, 3, 7, 5, { 0, _15TO8_8_8(9696), 2, 0, _15TO8_8_8(21151), 3 }, false },
+ { 8, 21, 4, { 11, 11, 10, 10, 9, 9 }, 4, 3, 8, 5, { 0, _15TO8_8_8(32738), 5, 0, _15TO8_8_8(0), 0 }, false },
+ { 9, 22, 0, { 11, 7, 11, 7, 11, 7 }, 3, 1, 9, 4, { 0, _15TO8_8_8(32356), 5, 0, _15TO8_8_8(17392), 3 }, false },
+ { 10, 23, 1, { 11, 11, 11, 11, 11, 11 }, 2, 1, 10, 2, { 0, _15TO8_8_8(6337), 1, 0, _15TO8_8_8(0), 0 }, false },
+ { 11, 24, 2, { 11, 11, 11, 11, 11, 11 }, 2, 1, 11, 2, { 1, _15TO8_8_8(32767), 7, 0, _15TO8_8_8(0), 0 }, false },
+ { -1 }, // skip
+ { 13, 24, 1, { 11, 11, 11, 11, 11, 11 }, 10, 5, 0, 30, { 0, _15TO8_8_8(0), 0, 0, _15TO8_8_8(0), 0 }, true }
+ };
+
+ character[player] = characterList[level];
+ return (character[player].picture != -1);
+}
+
+void PrepareStageGraphics( int type )
+{
+ int player;
+
+ MRect blobBoard = { 0, 0, kGridDown * kBlobVertSize, kGridAcross * kBlobHorizSize };
+
+ backgroundID = type * 100;
+
+ DrawPICTInSurface( boardSurface[0], picBoard + backgroundID );
+
+ // NOTE: Many levels have no right-side board, so we copy the left
+ // side over to the right side. This way, if DrawPICTInSurface flunks,
+ // we still have a valid picture.
+
+ SDLU_BlitSurface( boardSurface[0], &boardSurface[0]->clip_rect,
+ boardSurface[1], &boardSurface[1]->clip_rect );
+
+ DrawPICTInSurface( boardSurface[1], picBoardRight + backgroundID );
+
+ DrawPICTInSurface( backdropSurface, picBackdrop + backgroundID );
+
+ DrawPICTInSurface( nextSurface, picNext + backgroundID );
+
+ for( player=0; player<=1; player++ )
+ {
+ SDLU_AcquireSurface( playerSurface[player] );
+ SurfaceDrawBoard( player, &blobBoard );
+ SDLU_ReleaseSurface( playerSurface[player] );
+
+ CleanSpriteArea( player, &blobBoard );
+ }
+
+ BeginOpponent( type );
+
+ RedrawBoardContents( 0 );
+ RedrawBoardContents( 1 );
+
+ RefreshAll( );
+
+ backdropTicks = MTickCount( );
+ backdropFrame = 0;
+}
+
+void BeginRound( MBoolean changeMusic )
+{
+ int player, count, count2;
+
+ InitGrays( );
+ InitPotentialCombos( );
+
+ switch( players )
+ {
+ case 0:
+ case 1:
+ if( InitCharacter( 1, level ) )
+ {
+ score[1] = roundStartScore[1] = displayedScore[1] = 0;
+ character[0] = character[1];
+ character[0].zapStyle = RandomBefore(5);
+ }
+ else
+ {
+ TotalVictory( );
+ return;
+ }
+
+ if( control[1] == kNobodyControl )
+ {
+ InitRandom( 3 );
+ }
+ else
+ {
+ InitRandom( 5 );
+ }
+ break;
+
+ case 2:
+ score[0] = score[1] = roundStartScore[0] = roundStartScore[1] = displayedScore[0] = displayedScore[1] = 0;
+
+ InitRandom( 5 );
+
+ SelectRandomLevel( );
+ InitCharacter( 0, level );
+
+ SelectRandomLevel( );
+ InitCharacter( 1, level );
+
+ character[0].hints = (difficulty[0] == kEasyLevel) || (difficulty[0] == kMediumLevel);
+ character[1].hints = (difficulty[1] == kEasyLevel) || (difficulty[1] == kMediumLevel);
+ break;
+ }
+
+ for( player=0; player<=1; player++ )
+ {
+ for( count=0; count<kGridAcross; count++ )
+ {
+ grays[player][count] = 0;
+
+ for( count2=0; count2<kGridDown; count2++ )
+ {
+ grid[player][count][count2] = kEmpty;
+ suction[player][count][count2] = kNoSuction;
+ charred[player][count][count2] = kNoCharring;
+ glow[player][count][count2] = false;
+ }
+ }
+
+ nextA[player] = GetPiece( player );
+ nextB[player] = GetPiece( player );
+ nextM[player] = false;
+ nextG[player] = false;
+
+ halfway[player] = false;
+
+ unallocatedGrays[player] = 0;
+ anim[player] = 0;
+ lockGrays[player] = 0;
+ roundStartScore[player] = score[player];
+
+ RedrawBoardContents(player);
+
+ if( control[player] != kNobodyControl )
+ {
+ role[player] = kWaitForRetrieval;
+ }
+ else
+ {
+ role[player] = kIdlePlayer;
+ }
+ }
+
+ PrepareStageGraphics( character[1].picture );
+ if( changeMusic ) ChooseMusic( character[1].music );
+
+ blobTime[0] = blobTime[1] =
+ boredTime[0] = boredTime[1] =
+ hintTime[0] = hintTime[1] =
+ timeAI[0] = timeAI[1] =
+ fadeCharTime[0] = fadeCharTime[1] =
+ messageTime = startTime =
+ blinkTime[0] = blinkTime[1] = GameTickCount( );
+
+ blinkTime[1] += 60;
+
+ if( players == 2 )
+ InitDifficulty( );
+
+ SDLU_Present();
+}
+
+void IncrementLevel( void )
+{
+ level++;
+}
+
+void SelectRandomLevel( void )
+{
+ level = RandomBefore(kLevels) + 1;
+}
+
+void InitDifficulty( )
+{
+ MRect blobBoard = { 0, 0, kGridDown * kBlobVertSize, kGridAcross * kBlobHorizSize };
+ int player;
+ const int selectionRow = 5;
+ int count;
+ MRect blobRect;
+
+ for( player=0; player<=1; player++ )
+ {
+ // Set up variables
+ role[player] = kChooseDifficulty;
+ colorA[player] = RandomBefore(kBlobTypes)+1;
+ colorB[player] = kEmpty;
+ switch( difficulty[player] )
+ {
+ case kEasyLevel: blobX[player] = 1; break;
+ case kMediumLevel: blobX[player] = 2; break;
+ case kHardLevel: blobX[player] = 3; break;
+ case kUltraLevel: blobX[player] = 4; break;
+ }
+
+ blobY[player] = selectionRow;
+ blobR[player] = upRotate;
+ blobTime[player] = GameTickCount( ) + (60*8);
+ animTime[player] = GameTickCount( );
+ shadowDepth[player] = kBlobShadowDepth;
+ magic[player] = false;
+ grenade[player] = false;
+
+ DrawPICTInSurface( boardSurface[player], picSelectDifficulty + backgroundID );
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ SurfaceDrawBoard( player, &blobBoard );
+
+ grid[player][0][selectionRow] = kGray;
+ suction[player][0][selectionRow] = kEasyGray;
+ charred[player][0][selectionRow] = kNoCharring;
+ CalcBlobRect( 0, selectionRow, &blobRect );
+ SurfaceDrawBlob( player, &blobRect, kGray, kEasyGray, kNoCharring );
+
+ grid[player][kGridAcross-1][selectionRow] = kGray;
+ suction[player][kGridAcross-1][selectionRow] = kHardGray;
+ charred[player][kGridAcross-1][selectionRow] = kNoCharring;
+ CalcBlobRect( kGridAcross-1, selectionRow, &blobRect );
+ SurfaceDrawBlob( player, &blobRect, kGray, kHardGray, kNoCharring );
+
+ CalcBlobRect( 1, selectionRow, &blobRect );
+ blobRect.top -= 4; blobRect.bottom += 4;
+ blobRect.left += 4; blobRect.right -= 4;
+ for( count=1; count<=4; count++ )
+ {
+ DrawCharacter( count + '0', &blobRect );
+ OffsetMRect( &blobRect, kBlobHorizSize, 0 );
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+
+ DrawSpriteBlobs( player, kNoSuction );
+ CleanSpriteArea( player, &blobBoard );
+ }
+}
+
+void ChooseDifficulty( int player )
+{
+ MRect blobBoard = { 0, 0, kGridDown * kBlobVertSize, kGridAcross * kBlobHorizSize };
+ const int selectionRow = 5;
+ const int difficultyMap[kGridAcross] = {kEasyLevel, kEasyLevel, kMediumLevel, kHardLevel, kUltraLevel, kUltraLevel};
+ const int fallingSpeed[kGridAcross] = {0, 15, 9, 7, 4, 0};
+ const int startGrays[kGridAcross] = {0, 0, 0, 10, 20, 0};
+ const int difficultyFrame[] = { kNoSuction, blobBlinkAnimation, blobBlinkAnimation,
+ blobJiggleAnimation, blobCryAnimation, kNoSuction };
+ int oldX = blobX[player];
+
+ PlayerControl( player );
+ if( blobX[player] != oldX ) anim[player] = 0;
+
+ UpdateTweak( player, difficultyFrame[blobX[player]] );
+
+ if( GameTickCount( ) >= blobTime[player] )
+ {
+ if( player == 1 && PICTExists( picBoardRight + backgroundID ) )
+ {
+ DrawPICTInSurface( boardSurface[player], picBoardRight + backgroundID );
+ }
+ else
+ {
+ DrawPICTInSurface( boardSurface[player], picBoard + backgroundID );
+ }
+
+ SDLU_AcquireSurface( playerSurface[player] );
+ SurfaceDrawBoard( player, &blobBoard );
+ SDLU_ReleaseSurface( playerSurface[player] );
+
+ CleanSpriteArea( player, &blobBoard );
+
+ grid[player][0][selectionRow] = kEmpty;
+ grid[player][5][selectionRow] = kEmpty;
+
+ suction[player][0][selectionRow] = kNoSuction;
+ suction[player][5][selectionRow] = kNoSuction;
+
+ difficulty[player] = difficultyMap[ blobX[player] ];
+ character[player].dropSpeed = fallingSpeed[ blobX[player] ];
+ unallocatedGrays[player] = lockGrays[player] = startGrays[blobX[player]];
+ character[player].hints = (startGrays[blobX[player]] == 0);
+ role[player] = kWaitingToStart;
+
+ PlayStereoFrequency( player, kPause, player );
+ }
+}
+
+const char *gameCredits[][6] =
+{
+ { "Programming", "John Stiles", "", "", "", "" },
+ { "Artwork", "Kate Davis", "Leanne Stiles", "Arnauld de la Grandiere", "Bob Frasure", "Ryan Bliss" },
+ { "Music", "Leanne Stiles", "fmod", "Lizardking", "Armadon, Explizit", "Leviathan, Nemesis" },
+ { "Music", "Jester, Pygmy", "Siren", "Sirrus", "Scaven, FC", "Spring" },
+ { "Music", "Timewalker", "Jason, Silents", "Chromatic Dragon", "Ng Pei Sin", "" },
+ { "Source Port", "Iliyas Jorio", "github.com/jorio/candycrisis", "", "", "" },
+ { "Special Thanks", "Sam Lantinga", "Carey Lening", "modarchive.com", "digitalblasphemy.com", "" },
+ { "", "", "", "", "", "" }
+};
+
+void SharewareVictory( void )
+{
+ SkittlesFontPtr textFont, titleFont;
+ SDL_Surface* backBuffer;
+ SDL_Surface* frontBuffer;
+ SDL_Rect creditSrcSDLRect, bufferSrcSDLRect, bufferDstSDLRect;
+ MRect creditSrcRect = { 0, 0, 369, 150 };
+ MRect bufferSrcRect = { 0, 50, 480, 350 };
+ MRect bufferDstRect = { 0, 0, 480, 300 };
+ MPoint dPoint = { 450, 50 }, lPoint, cPoint;
+ int scroll, x, y;
+ MTicks ticks;
+ const char* text;
+ int thisFade;
+ const char fade[120] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0
+ 1, 2, 3, 4, 5, 6, 7, 8, 9,10, //1
+ 11,12,13,14,15,16,17,18,19,20, //2
+ 20,20,20,20,20,20,20,20,20,20, //3
+ 20,20,20,20,20,20,20,20,20,20, //4
+ 20,20,20,20,20,20,20,20,20,20, //5
+ 20,20,20,20,20,20,20,20,20,20, //6
+ 20,20,20,20,20,20,20,20,20,20, //7
+ 20,20,20,20,20,20,20,20,20,20, //8
+ 20,19,18,17,16,15,14,13,12,11, //9
+ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, //10
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 //11
+ };
+
+ titleFont = GetFont( picFont );
+ textFont = GetFont( picTinyFont );
+
+ SDLU_MRectToSDLRect( &creditSrcRect, &creditSrcSDLRect );
+ SDLU_MRectToSDLRect( &bufferSrcRect, &bufferSrcSDLRect );
+ SDLU_MRectToSDLRect( &bufferDstRect, &bufferDstSDLRect );
+
+ DrawPICTInSurface( g_frontSurface, picSharewareVictory );
+ SDLU_Present();
+
+ backBuffer = SDLU_InitSurface( &bufferDstSDLRect, 32 );
+
+ SDLU_BlitSurface( g_frontSurface, &bufferSrcSDLRect,
+ backBuffer, &bufferDstSDLRect );
+
+ frontBuffer = SDLU_InitSurface( &bufferDstSDLRect, 32 );
+
+ QuickFadeIn( NULL );
+
+ ChooseMusic( 12 );
+
+ ticks = MTickCount();
+ for( scroll=0; scroll<1500; scroll++ )
+ {
+ SDLU_AcquireSurface( frontBuffer );
+
+ SDLU_BlitSurface( backBuffer, &bufferDstSDLRect,
+ frontBuffer, &bufferDstSDLRect );
+
+ ticks += 3;
+ lPoint = dPoint;
+ for( y=0; y<8; y++ )
+ {
+ if( y != 3 && y != 4 )
+ {
+ cPoint.v = lPoint.v + 25;
+ cPoint.h = lPoint.h;
+ if( cPoint.v > 480 ) break;
+
+ if( cPoint.v > 0 )
+ {
+ text = gameCredits[y][0];
+ thisFade = fade[cPoint.v >> 2];
+
+ while( *text )
+ {
+ SurfaceBlitWeightedCharacter( titleFont, *text++, &cPoint, 255, 255, 0, _5TO8(thisFade) );
+ }
+ }
+
+ lPoint.v += 50;
+ }
+
+ for( x=1; x<6; x++ )
+ {
+ if( gameCredits[y][x][0] )
+ {
+ cPoint.v = lPoint.v;
+ cPoint.h = lPoint.h + 20;
+ if( cPoint.v > 480 ) break;
+
+ if( cPoint.v > 0 )
+ {
+ text = gameCredits[y][x];
+ thisFade = fade[cPoint.v >> 2];
+
+ while( *text )
+ {
+ SurfaceBlitWeightedCharacter( textFont, *text++, &cPoint, 255, 255, 0, _5TO8(thisFade) );
+ }
+ }
+
+ lPoint.v += 20;
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( frontBuffer );
+
+ dPoint.v--;
+
+ SDLU_BlitFrontSurface( frontBuffer, &bufferDstSDLRect, &bufferSrcSDLRect );
+ SDLU_Present();
+
+ do
+ {
+ if( SDLU_Button() ) goto out;
+ SDLU_Yield();
+ }
+ while( ticks >= MTickCount() );
+ }
+
+ do
+ {
+ SDLU_Yield();
+ }
+ while( !AnyKeyIsPressed( ) && !SDLU_Button() );
+
+out:
+ QuickFadeOut( NULL );
+
+ SDL_FreeSurface( backBuffer );
+ SDL_FreeSurface( frontBuffer );
+}
+
+void RegisteredVictory( void )
+{
+ SkittlesFontPtr textFont, titleFont, bubbleFont;
+ SDL_Surface* backBuffer;
+ SDL_Surface* frontBuffer;
+ MPoint dPoint[] = { { 230, 340 }, { 230, 30 }, { 230, 30 }, { 30, 30 }, { 30, 340 }, { 230, 340 }, { 230, 30 } };
+ MPoint bubblePoint, textPoint, shadowPoint;
+ MPoint setPoint[7][6];
+ MPoint msgSetPoint[7][2];
+ MTicks ticks;
+ int vertScroll, picture, weight, line, minimum;
+ int scrollDir[] = {1, -1, 1, -1, 1, -1, -1};
+ int spacing[] = {40, 19, 19, 19, 23, 19, 23 };
+ const char* text;
+ SDL_Rect fullSDLRect = { 0, 0, 640, 480 };
+ SDL_Rect highSDLRect = { 0, 0, 640, 480 };
+ SDL_Rect lowSDLRect = { 0, 250, 640, 480 };
+ SDL_Rect backBufferSDLRect = { 0, 0, 640, 730 };
+ SDL_Rect scrollSDLRect;
+
+ const char *messages[7][2] =
+ {
+ { "Congratulations!", "" },
+ { "You've managed to vaporize all", "of the rampaging candies!" },
+ { "Your quick thinking and sharp", "reflexes have saved the day." },
+ { "", "" },
+ { "", "" },
+ { "", "" },
+ { "Thanks for playing Candy Crisis!", "" },
+ };
+
+ // In widescreen mode, move vertical text positions closer to the center
+ if (widescreen)
+ {
+ for (int i = 0; i < arrsize(dPoint); i++)
+ {
+ if (dPoint[i].v >= 130)
+ dPoint[i].v -= 20;
+ else
+ dPoint[i].v += 20;
+ }
+ }
+
+ textFont = GetFont( picTinyFont );
+ titleFont = GetFont( picHiScoreFont );
+ bubbleFont = GetFont( picBubbleFont );
+
+ ChooseMusic( 14 );
+
+ for( picture=0; picture<7; picture++ )
+ {
+ for( line=0; line<2; line++ )
+ {
+ if (dPoint[picture].v >= 130) {
+ msgSetPoint[picture][line].v = (widescreen? 120: 100) + line * 30;
+ } else {
+ msgSetPoint[picture][line].v = (widescreen? 380: 300) + line * 30;
+ }
+ msgSetPoint[picture][line].h = 320 - (GetTextWidth( titleFont, messages[picture][line] ) / 2);
+ }
+
+ for( line=0; line<6; line++ )
+ {
+ SkittlesFontPtr font;
+
+ if( line == 0 )
+ {
+ font = titleFont;
+ textPoint.v = 45;
+ }
+ else
+ {
+ font = textFont;
+ textPoint.v = 65 + (spacing[picture] * line);
+ }
+
+ textPoint.h = (bubbleFont->width['*'] - GetTextWidth( font, gameCredits[picture][line] )) / 2;
+
+ setPoint[picture][line].v = dPoint[picture].v + textPoint.v;
+ setPoint[picture][line].h = dPoint[picture].h + textPoint.h;
+ }
+
+ minimum = 640;
+ for( line=1; line<6; line++ )
+ {
+ if( setPoint[picture][line].h < minimum ) minimum = setPoint[picture][line].h;
+ }
+
+ for( line=1; line<6; line++ )
+ {
+ setPoint[picture][line].h = minimum;
+ }
+ }
+
+ backBuffer = SDLU_InitSurface( &backBufferSDLRect, 32 );
+ frontBuffer = SDLU_InitSurface( &fullSDLRect, 32 );
+
+ for( picture = 0; picture<7; picture++ )
+ {
+ scrollSDLRect = ( scrollDir[picture] > 0 )? highSDLRect: lowSDLRect;
+
+ DrawPICTInSurface( backBuffer, picture + picVictory1 );
+
+ SDLU_BlitFrontSurface( backBuffer, &scrollSDLRect, &fullSDLRect );
+ SDLU_Present();
+
+ QuickFadeIn( NULL );
+
+ ticks = MTickCount();
+ for( vertScroll = 0; vertScroll < 250; vertScroll++ )
+ {
+ SDLU_AcquireSurface( frontBuffer );
+
+ SDLU_BlitSurface( backBuffer, &scrollSDLRect,
+ frontBuffer, &fullSDLRect );
+
+ weight = vertScroll - 20;
+ for( line=0; line<2; line++ )
+ {
+ textPoint = msgSetPoint[picture][line];
+ shadowPoint.v = textPoint.v + 1;
+ shadowPoint.h = textPoint.h + 1;
+
+ text = messages[picture][line];
+
+ while( *text && weight > 0 )
+ {
+ int fixedWeight = (weight > 31)? 31: weight;
+
+ SurfaceBlitWeightedCharacter( titleFont, *text, &shadowPoint, 0, 0, 0, _5TO8(fixedWeight) );
+ SurfaceBlitWeightedCharacter( titleFont, *text, &textPoint, 255, 255, 255, _5TO8(fixedWeight) );
+ weight--;
+ text++;
+ }
+ }
+
+ bubblePoint = dPoint[picture];
+ weight = ( vertScroll <= 210 )? vertScroll - 10: 241 - vertScroll;
+ if( weight < 0 ) weight = 0;
+ if( weight > 31 ) weight = 31;
+
+ if( weight > 0 )
+ {
+ int bubbleWeight = (weight+1)>>1;
+
+ SurfaceBlitWeightedCharacter( bubbleFont, '*', &bubblePoint, 255, 255, 255, _5TO8(bubbleWeight) );
+
+ for( line=0; line<6; line++ )
+ {
+ SkittlesFontPtr font = (line == 0)? titleFont: textFont;
+
+ textPoint = setPoint[picture][line];
+ text = gameCredits[picture][line];
+
+ while( *text )
+ {
+ SurfaceBlitWeightedCharacter( font, *text++, &textPoint, 0, 0, 0, _5TO8(weight) );
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( frontBuffer );
+
+ SDLU_BlitFrontSurface( frontBuffer, &fullSDLRect, &fullSDLRect );
+ SDLU_Present();
+
+ scrollSDLRect.y += scrollDir[picture];
+
+ ticks += 4;
+ do
+ {
+ if( SDLU_Button() ) vertScroll = 250;
+ SDLU_Yield();
+ }
+ while( ticks >= MTickCount() );
+ }
+
+ QuickFadeOut( NULL );
+ }
+
+ SDL_FreeSurface( backBuffer );
+ SDL_FreeSurface( frontBuffer );
+}
+
+void TotalVictory( void )
+{
+ AddHiscore( score[0] );
+ QuickFadeOut( NULL );
+
+ DoFullRepaint = NoPaint;
+
+ RegisteredVictory( );
+
+ showStartMenu = true;
+}
--- a/src/level.cpp
+++ /dev/null
@@ -1,1438 +1,0 @@
-// level.c
-
-#include <stdlib.h>
-#include <math.h>
-#include <algorithm>
-
-#include "SDLU.h"
-
-#include "main.h"
-#include "level.h"
-#include "score.h"
-#include "random.h"
-#include "grays.h"
-#include "gameticks.h"
-#include "players.h"
-#include "graymonitor.h"
-#include "opponent.h"
-#include "gworld.h"
-#include "graphics.h"
-#include "music.h"
-#include "control.h"
-#include "tweak.h"
-#include "soundfx.h"
-#include "next.h"
-#include "hiscore.h"
-#include "victory.h"
-#include "blitter.h"
-#include "zap.h"
-#include "keyselect.h"
-#include "tutorial.h"
-#include "pause.h"
-
-MRect stageWindowZRect, stageWindowRect;
-Character character[2];
-int level, players, credits, difficulty[2] = {kHardLevel, kHardLevel};
-int difficultyTicks, backdropTicks, backdropFrame;
-
-#define kNumSplats 16
-#define kIdleSplat -2
-#define kFallingSplat -1
-#define kTitleItems 8
-#define kIncrementPerFrame 2
-#define kSplatType 4
-
-using std::min;
-using std::max;
-
-const int startSkip = 1;
-static MBoolean shouldFullRepaint = false;
-static MTicks startMenuTime = 0;
-static int splatState[kNumSplats], splatColor[kNumSplats], splatSide[kNumSplats];
-static MRect splatBlob[kNumSplats];
-
-enum
-{
- kTitleItemTutorial,
- kTitleItem1PGame,
- kTitleItem2PGame,
- kTitleItemSolitaire,
- kTitleItemHighScores,
- kTitleItemControls,
- kTitleItemCredits,
- kTitleItemQuit,
-};
-
-struct TitleItemDef
-{
- const char* name;
- MRGBColor color1;
- MRGBColor color2;
- MRect rect;
-};
-
-static const TitleItemDef k_titleItemDefs[kTitleItems] =
-{
- { "\x03 Tutorial Mode", {204, 67,137}, {101, 74,207}, {155, 203, 207, 426} },
- { "\x03 One Player Game", { 35, 31,240}, { 81,237,252}, {225, 179, 281, 451} },
- { "\x03 Two Player Game", {212,194, 48}, {255,196, 56}, {297, 182, 352, 454} },
- { "\x03 Solitaire Crisis", {102,247,106}, {125,237,179}, {358, 183, 428, 458} },
- { "\x03 High Scores", {234,244,132}, {192,218, 85}, {429, 280, 478, 390} },
- { "\x03 Controls", { 64, 88,212}, { 62, 87,205}, {430, 187, 479, 280} },
- { "\x03 Credits", {245, 7, 78}, {254,128,156}, { 6, 370, 59, 423} },
- { "\x03 Quit", {107,105,106}, {169,167,168}, {433, 390, 477, 446} }
-};
-
-const int kCursorWidth = 32;
-const int kCursorHeight = 32;
-
-#if USE_CURSOR_SPRITE
-static void InsertCursor( MPoint mouseHere, SDL_Surface* scratch, SDL_Surface* surface )
-{
- SkittlesFontPtr cursorFont = GetFont( picFont );
- SDL_Rect cursorBackSDLRect = { 0, 0, kCursorWidth, kCursorHeight };
- SDL_Rect cursorFrontSDLRect = { 0, 0, kCursorWidth, kCursorHeight };
- MPoint mouseHereToo = mouseHere;
-
- cursorFrontSDLRect.x = mouseHere.h;
- cursorFrontSDLRect.y = mouseHere.v;
-
- SDLU_BlitSurface( surface, &cursorFrontSDLRect,
- scratch, &cursorBackSDLRect );
-
- SDLU_AcquireSurface( surface );
- SurfaceBlitCharacter( cursorFont, '\x05', &mouseHere, 0, 0, 0, 0 );
- SurfaceBlitCharacter( cursorFont, '\x04', &mouseHereToo, 255, 255, 255, 0 );
- SDLU_ReleaseSurface( surface );
-}
-
-static void RemoveCursor( MPoint mouseHere, SDL_Surface* scratch, SDL_Surface* surface )
-{
- SDL_Rect cursorBackSDLRect = { 0, 0, kCursorWidth, kCursorHeight };
- SDL_Rect cursorFrontSDLRect = { 0, 0, kCursorWidth, kCursorHeight };
-
- cursorFrontSDLRect.x = mouseHere.h;
- cursorFrontSDLRect.y = mouseHere.v;
-
- SDLU_BlitSurface( scratch, &cursorBackSDLRect,
- surface, &cursorFrontSDLRect );
-}
-#endif
-
-static void GameStartMenuRepaint()
-{
- shouldFullRepaint = true;
-}
-
-void GameStartMenu( void )
-{
- MBoolean useNewTitle = widescreen;
-
- // NOTE: be wary of initializing variables here! This function can run top-to-bottom
- // multiple times in a row, thanks to "redo". Put initializations after redo.
- SDL_Surface* gameStartSurface;
- SDL_Surface* gameStartDrawSurface;
-#if USE_CURSOR_SPRITE
- SDL_Surface* cursorBackSurface;
-#endif
- SDL_Rect backdropSDLRect = { 0, 0, 640, 480 };
- SDL_Rect cursorBackSDLRect = { 0, 0, kCursorWidth, kCursorHeight };
- SDL_Rect destSDLRect;
- MRect drawRect[4], chunkRect, tempRect;
- int blob, count, oldGlow, splat, chunkType, selected;
- int skip;
- MPoint mouse;
- MPoint dPoint;
- unsigned int black;
- int combo[2], comboBright[2], missBright[2];
- SkittlesFontPtr smallFont = GetFont( picFont );
- SkittlesFontPtr tinyFont = GetFont( picTinyFont );
- SDL_Rect meterRect[2] = { { 30, 360, 110, 20 }, { 530, 360, 110, 20 } };
- TitleItemDef titleItems[kTitleItems];
- int titleGlow[kTitleItems];
- int shouldAddBlob;
- const int kTitleGlowOff = useNewTitle? 150: 192;
- const bool secretCreditsItem = !useNewTitle;
-
- const int kLeftSide = 0, kRightSide = 1, kGlow = 2, kCursor = 3;
-
-
-redo:
- memcpy(titleItems, k_titleItemDefs, sizeof(titleItems));
-
- combo[0] = combo[1] = 0;
- comboBright[0] = comboBright[1] = 0;
- missBright[0] = missBright[1] = 0;
-
- skip = 1;
- selected = -1;
- mouse.h = mouse.v = 0;
-
- if( finished ) return;
-
- if( musicSelection != 13 ) ChooseMusic( 13 );
-
- for( count=0; count<kTitleItems; count++ )
- {
- titleGlow[count] = kTitleGlowOff;
- }
-
- if (secretCreditsItem)
- {
- titleGlow[kTitleItemCredits] = 0;
- }
-
- for( count=0; count<kNumSplats; count++ )
- {
- splatState[count] = kIdleSplat;
- }
-
- // make background surface
- gameStartSurface = LoadPICTAsSurface( picGameStart, 32 );
- black = SDL_MapRGB( gameStartSurface->format, 0, 0, 0 );
-
- // make cursor backing store
-#if USE_CURSOR_SPRITE
- cursorBackSurface = SDLU_InitSurface( &cursorBackSDLRect, 32 );
- SDL_FillRect( cursorBackSurface, &cursorBackSDLRect, black );
-#endif
-
- // make drawing surface
- gameStartDrawSurface = SDLU_InitSurface( &backdropSDLRect, 32 );
- if (!useNewTitle)
- {
- SDLU_BlitSurface(gameStartSurface, &gameStartSurface->clip_rect,
- gameStartDrawSurface, &gameStartDrawSurface->clip_rect);
- }
- else
- {
- // Prepare new title screen
- SDL_FillRect(gameStartDrawSurface, &gameStartDrawSurface->clip_rect, black);
-
- // Copy logo from original title screen to where we want it
- SDL_Rect r1 = {0, 0, 640, 150};
- SDL_Rect r2 = {0, 70, 640, 150};
- SDLU_BlitSurface(gameStartSurface, &r1, gameStartDrawSurface, &r2);
-
- // Now we're going to draw title items on gameStartSurface
- SDL_FillRect(gameStartSurface, &gameStartSurface->clip_rect, black);
- SDLU_AcquireSurface(gameStartSurface);
-
- SkittlesFontPtr font = GetFont(picFont);
- int left = 225;
- dPoint.h = left;
- dPoint.v = 215;
- for (int i = 0; i < kTitleItems; i++)
- {
- auto &item = titleItems[i];
- item.rect.left = dPoint.h;
- item.rect.top = dPoint.v - 6;
- item.rect.bottom = dPoint.v + 16 + 6;
- auto nameLength = strlen(item.name);
- for (int charNo = 0; charNo < nameLength; charNo++)
- {
- char c = item.name[charNo];
- float p = charNo / (float) (nameLength - 1);
- int red = item.color1.red * (1.0f - p) + item.color2.red * p;
- int green = item.color1.green * (1.0f - p) + item.color2.green * p;
- int blue = item.color1.blue * (1.0f - p) + item.color2.blue * p;
- SurfaceBlitCharacter(font, c, &dPoint, red, green, blue, 1);
- }
- item.rect.right = dPoint.h;
- dPoint.h = left;
- dPoint.v += 24;
- }
- SDLU_ReleaseSurface(gameStartSurface);
- }
-
- // darken menu items
- for( count=0; count<kTitleItems; count++ )
- {
- SurfaceBlitColorOver( gameStartSurface, gameStartDrawSurface,
- &titleItems[count].rect, &titleItems[count].rect,
- 0, 0, 0, titleGlow[count] );
- }
-
- SDLU_BlitFrontSurface( gameStartDrawSurface, &backdropSDLRect, &backdropSDLRect );
- SDLU_Present();
-
- WaitForRelease();
-
- QuickFadeIn( NULL );
-
- DoFullRepaint = GameStartMenuRepaint;
-
- shouldAddBlob = 5;
- startMenuTime = MTickCount( );
- while( ( selected == -1 || !SDLU_Button() ) && !finished )
- {
- startMenuTime += skip;
-
- UpdateSound();
-
- // Add a new falling blob
- --shouldAddBlob;
- if (shouldAddBlob <= 0)
- {
- for( blob=0; blob<kNumSplats; blob++ )
- {
- if( splatState[blob] == kIdleSplat )
- {
- splatSide[blob] = RandomBefore(2);
- splatBlob[blob].top = -24 - RandomBefore(15);
- splatBlob[blob].left = (splatSide[blob] == 0)? RandomBefore( 110 ): 640 - kBlobHorizSize - RandomBefore( 110 );
- splatBlob[blob].bottom = splatBlob[blob].top + kBlobVertSize;
- splatBlob[blob].right = splatBlob[blob].left + kBlobHorizSize;
- splatColor[blob] = ((startMenuTime >> 2) % kBlobTypes) + 1;
- splatState[blob] = kFallingSplat;
-
- break;
- }
- }
- shouldAddBlob = 5;
- }
-
- // Erase and redraw falling blobs and chunks
-
- SDLU_AcquireSurface( gameStartDrawSurface );
-
- // Take the cursor out of the scene
-#if USE_CURSOR_SPRITE
- RemoveCursor( mouse, cursorBackSurface, gameStartDrawSurface );
- drawRect[kCursor].top = mouse.v;
- drawRect[kCursor].left = mouse.h;
- drawRect[kCursor].bottom = mouse.v + kCursorHeight;
- drawRect[kCursor].right = mouse.h + kCursorWidth;
-#endif
-
- // Inverted rectangles mean "nothing to do."
- drawRect[kLeftSide].top = drawRect[kRightSide].top = drawRect[kGlow].top =
- drawRect[kLeftSide].left = drawRect[kRightSide].left = drawRect[kGlow].left = 9999;
- drawRect[kLeftSide].bottom = drawRect[kRightSide].bottom = drawRect[kGlow].bottom =
- drawRect[kLeftSide].right = drawRect[kRightSide].right = drawRect[kGlow].right = -9999;
-
- // Get cursor position
- SDLU_GetMouse( &mouse );
- if( mouse.v > (widescreen ? 400 : 460) )
- mouse.v = (widescreen ? 400 : 460);
-
- // Erase falling blobs
- for( blob=0; blob<kNumSplats; blob++ )
- {
- if( splatState[blob] == kFallingSplat )
- {
- SDL_FillRect( gameStartDrawSurface, SDLU_MRectToSDLRect( &splatBlob[blob], &destSDLRect ), black );
- UnionMRect( &drawRect[splatSide[blob]], &splatBlob[blob], &drawRect[splatSide[blob]] );
-
- OffsetMRect( &splatBlob[blob], 0, startSkip * (6 + (splatBlob[blob].bottom / 20)) );
- }
- else if( splatState[blob] >= kIncrementPerFrame )
- {
- for( splat=-3; splat<=3; splat++ )
- {
- if( splat )
- {
- chunkRect = splatBlob[blob];
- GetZapStyle( 0, &chunkRect, &splatColor[blob], &chunkType, splat, splatState[blob]-kIncrementPerFrame, kSplatType );
- SDL_FillRect( gameStartDrawSurface, SDLU_MRectToSDLRect( &chunkRect, &destSDLRect ), black );
- UnionMRect( &drawRect[splatSide[blob]], &chunkRect, &drawRect[splatSide[blob]] );
- }
- }
-
- SDL_FillRect( gameStartDrawSurface, SDLU_MRectToSDLRect( &splatBlob[blob], &destSDLRect ), black );
- UnionMRect( &drawRect[splatSide[blob]], &splatBlob[blob], &drawRect[splatSide[blob]] );
- }
- }
-
- // Draw combo meters
-
- for( count=0; count<2; count++ )
- {
- int bright = comboBright[count];
- int mBright = missBright[count];
- if( bright || mBright )
- {
- SDL_FillRect( gameStartDrawSurface, &meterRect[count], black );
- UnionMRect( &drawRect[count], SDLU_SDLRectToMRect( &meterRect[count], &tempRect ), &drawRect[count] );
-
- if( mBright > 1 )
- {
- dPoint.v = meterRect[count].y;
- dPoint.h = meterRect[count].x + 10;
- SurfaceBlitCharacter( smallFont, 'M', &dPoint, mBright, mBright >> 2, mBright >> 2, 1 );
- SurfaceBlitCharacter( smallFont, 'I', &dPoint, mBright, mBright >> 2, mBright >> 2, 1 );
- SurfaceBlitCharacter( smallFont, 'S', &dPoint, mBright, mBright >> 2, mBright >> 2, 1 );
- SurfaceBlitCharacter( smallFont, 'S', &dPoint, mBright, mBright >> 2, mBright >> 2, 1 );
- missBright[count] -= 8;
- }
- else if( (combo[count] >= 10) && (bright > 1) )
- {
- char number[16] = { 0 };
- char* scan;
- sprintf( number, "%d", combo[count] );
-
- dPoint.v = meterRect[count].y + 3;
- dPoint.h = meterRect[count].x;
-
- SurfaceBlitCharacter( tinyFont, 'C', &dPoint, bright, bright, bright, 1 );
- SurfaceBlitCharacter( tinyFont, 'O', &dPoint, bright, bright, bright, 1 );
- SurfaceBlitCharacter( tinyFont, 'M', &dPoint, bright, bright, bright, 1 );
- SurfaceBlitCharacter( tinyFont, 'B', &dPoint, bright, bright, bright, 1 );
- SurfaceBlitCharacter( tinyFont, 'O', &dPoint, bright, bright, bright, 1 );
- SurfaceBlitCharacter( tinyFont, ' ', &dPoint, bright, bright, bright, 1 );
- dPoint.v -= 3;
-
- for( scan = number; *scan; scan++ )
- {
- SurfaceBlitCharacter( smallFont, *scan, &dPoint, bright>>2, bright>>2, bright, 1 );
- }
-
- comboBright[count] -= 16;
- }
- else
- {
- comboBright[count] = 0;
- }
- }
- }
-
- // Redraw falling blobs
- for( blob=0; blob<kNumSplats; blob++ )
- {
- if( splatState[blob] == kFallingSplat )
- {
- int bottom = widescreen? 420: 480;
- if( splatBlob[blob].bottom >= bottom )
- {
- splatBlob[blob].top = bottom - kBlobVertSize;
- splatBlob[blob].bottom = bottom;
- splatState[blob] = 1;
-
- // Process combos
- if( mouse.v > bottom &&
- mouse.h >= (splatBlob[blob].left - 30) &&
- mouse.h <= (splatBlob[blob].right + 10) )
- {
- combo[splatSide[blob]]++;
- comboBright[splatSide[blob]] = 255;
- }
- else
- {
- if( combo[splatSide[blob]] >= 10 ) missBright[splatSide[blob]] = 255;
- combo[splatSide[blob]] = 0;
- comboBright[splatSide[blob]] = 0;
- }
- }
- else
- {
- SurfaceDrawSprite( &splatBlob[blob], splatColor[blob], kNoSuction );
- UnionMRect( &drawRect[splatSide[blob]], &splatBlob[blob], &drawRect[splatSide[blob]] );
- }
- }
-
- if( splatState[blob] >= 0 && splatState[blob] <= kZapFrames )
- {
- if( splatState[blob] <= (kZapFrames - kIncrementPerFrame) )
- {
- chunkType = 0;
-
- for( splat=-3; splat<=3; splat++ )
- {
- if( splat )
- {
- chunkRect = splatBlob[blob];
- GetZapStyle( 0, &chunkRect, &splatColor[blob], &chunkType, splat, splatState[blob], kSplatType );
- SurfaceDrawSprite( &chunkRect, splatColor[blob], chunkType );
- UnionMRect( &drawRect[splatSide[blob]], &chunkRect, &drawRect[splatSide[blob]] );
- }
- }
-
- SurfaceDrawSprite( &splatBlob[blob], splatColor[blob], chunkType );
- UnionMRect( &drawRect[splatSide[blob]], &splatBlob[blob], &drawRect[splatSide[blob]] );
- }
-
- splatState[blob] += kIncrementPerFrame;
- if( splatState[blob] > kZapFrames ) splatState[blob] = kIdleSplat;
- }
- }
-
- SDLU_ReleaseSurface( gameStartDrawSurface );
-
- // Find mouse coords
-
- selected = -1;
- for( count=0; count<kTitleItems; count++ )
- {
- if( MPointInMRect( mouse, &titleItems[count].rect ) )
- {
- selected = count;
- break;
- }
- }
-
- if (secretCreditsItem)
- {
- titleGlow[kTitleItemCredits] = 0;
- }
-
- // update glows
- for (int glowUpdate=0; glowUpdate < kTitleItems; ++glowUpdate)
- {
- const MRect& titleRect = titleItems[glowUpdate].rect;
- oldGlow = titleGlow[glowUpdate];
-
- if( selected == glowUpdate )
- {
- titleGlow[glowUpdate] -= (6 * startSkip);
- if( titleGlow[glowUpdate] < 0 ) titleGlow[glowUpdate] = 0;
- }
- else
- {
- titleGlow[glowUpdate] += (6 * startSkip);
- if( titleGlow[glowUpdate] > kTitleGlowOff ) titleGlow[glowUpdate] = kTitleGlowOff;
- }
-
- if( titleGlow[glowUpdate] != oldGlow )
- {
- SurfaceBlitColorOver( gameStartSurface, gameStartDrawSurface,
- &titleRect, &titleRect,
- 0, 0, 0, titleGlow[glowUpdate] );
-
- drawRect[kGlow].top = min<short>(drawRect[kGlow].top, titleRect.top);
- drawRect[kGlow].left = min<short>(drawRect[kGlow].left, titleRect.left);
- drawRect[kGlow].bottom = max<short>(drawRect[kGlow].bottom, titleRect.bottom);
- drawRect[kGlow].right = max<short>(drawRect[kGlow].right, titleRect.right);
- }
- }
-
- // Reinsert the cursor into the scene
-#if USE_CURSOR_SPRITE
- InsertCursor( mouse, cursorBackSurface, gameStartDrawSurface );
- drawRect[kCursor].top = min<short>( drawRect[kCursor].top, mouse.v );
- drawRect[kCursor].left = min<short>( drawRect[kCursor].left, mouse.h );
- drawRect[kCursor].bottom = max<short>( drawRect[kCursor].bottom, mouse.v + kCursorHeight );
- drawRect[kCursor].right = max<short>( drawRect[kCursor].right, mouse.h + kCursorWidth );
-#endif
- SDLU_SetSystemCursor( selected < 0 ? SYSTEM_CURSOR_ARROW : SYSTEM_CURSOR_HAND );
-
- // Copy down everything
- if( shouldFullRepaint )
- {
- SDLU_BlitFrontSurface( gameStartDrawSurface, &gameStartDrawSurface->clip_rect, &gameStartDrawSurface->clip_rect );
- shouldFullRepaint = false;
- }
- else
- {
- for( count=0; count<4; count++ )
- {
- if( drawRect[count].left < drawRect[count].right )
- {
- SDLU_MRectToSDLRect( &drawRect[count], &destSDLRect );
- SDLU_BlitFrontSurface( gameStartDrawSurface, &destSDLRect, &destSDLRect );
- }
- }
- }
-
- SDLU_Present();
-
- // Skip frames? Or delay?
- if( startMenuTime <= MTickCount( ) )
- {
- startMenuTime = MTickCount( );
- skip = 2;
- }
- else
- {
- skip = 1;
- while( startMenuTime > MTickCount( ) )
- {
- SDLU_Yield();
- }
- }
- }
-
- DoFullRepaint = NoPaint;
-
- if( finished )
- {
- selected = kTitleItemQuit;
- }
- else
- {
- SDLU_SetSystemCursor( SYSTEM_CURSOR_OFF );
- }
-
- switch( selected )
- {
- case kTitleItemTutorial:
- case kTitleItem1PGame:
- case kTitleItem2PGame:
- case kTitleItemSolitaire:
- PlayMono( kChime );
- break;
- }
-
- SDL_FreeSurface( gameStartSurface );
- SDL_FreeSurface( gameStartDrawSurface );
-#if USE_CURSOR_SPRITE
- SDL_FreeSurface( cursorBackSurface );
-#endif
-
- QuickFadeOut( NULL );
-
- switch( selected )
- {
- case kTitleItemTutorial:
- InitGame( kAutoControl, kNobodyControl );
- level = kTutorialLevel;
- BeginRound( true );
- InitTutorial( );
- QuickFadeIn( NULL );
- break;
-
- case kTitleItem1PGame:
- case kTitleItem2PGame:
- case kTitleItemSolitaire:
- {
- int player2[] = { 0, kAIControl, kPlayerControl, kNobodyControl };
-
- InitGame( kPlayerControl, player2[selected] );
- BeginRound( true );
- QuickFadeIn( NULL );
- break;
- }
-
- case kTitleItemHighScores:
- ShowHiscore();
- ShowBestCombo();
- break;
-
- case kTitleItemControls:
- {
- int currentID = RandomBefore(kLevels) * 100;
-
- DrawPICTInSurface( boardSurface[0], picBoard + currentID );
- DrawPICTInSurface( g_frontSurface, picBackdrop + currentID );
- SDLU_Present();
-
- QuickFadeIn( NULL );
- HandleDialog( kControlsDialog );
- QuickFadeOut( NULL );
- goto redo;
- }
-
- case kTitleItemCredits:
- {
- SharewareVictory();
- goto redo;
- }
-
- case kTitleItemQuit:
- finished = true;
- break;
- }
-}
-
-void ShowGameOverScreen( void )
-{
- unsigned int timer = MTickCount() + (60*3);
-
- QuickFadeOut(NULL);
-
- DrawPICTInSurface( g_frontSurface, picGameOver );
-
- SDL_Rect widescreenCropBackup = g_widescreenCrop;
- g_widescreenCrop.y = 30;
-
- SDLU_Present();
-
- QuickFadeIn( NULL );
- do
- {
- if( MTickCount() > timer ) break;
- SDLU_Yield();
- }
- while( !AnyKeyIsPressed( ) && !SDLU_Button() );
- QuickFadeOut( NULL );
-
- g_widescreenCrop = widescreenCropBackup;
-}
-
-void InitStage( void )
-{
- stageWindowZRect.top = stageWindowZRect.left = 0;
- stageWindowZRect.bottom = 32; stageWindowZRect.right = 64;
-
- stageWindowRect = stageWindowZRect;
- CenterRectOnScreen( &stageWindowRect, 0.5, 0.65 );
-}
-
-void DrawStage( void )
-{
- SDL_Surface* levelSurface;
- SDL_Rect sourceSDLRect, destSDLRect;
- MRect numberRect = { 0, kNumberHorizSize/8, kNumberVertSize, kNumberHorizSize*9/8 };
-
- switch( players )
- {
- case 0:
- case 2:
- break;
-
- case 1:
- SDLU_MRectToSDLRect( &stageWindowZRect, &sourceSDLRect );
- SDLU_MRectToSDLRect( &stageWindowRect, &destSDLRect );
-
- levelSurface = SDLU_InitSurface( &sourceSDLRect, 32 );
-
- SDLU_AcquireSurface( levelSurface );
-
- SDLU_BlitSurface( boardSurface[0], &sourceSDLRect,
- levelSurface, &sourceSDLRect );
-
- if( level < 10 )
- {
- OffsetMRect( &numberRect, kNumberHorizSize*3/8, 0 );
- }
-
- DrawCharacter( kCharacterStage, &numberRect );
- OffsetMRect( &numberRect, kNumberHorizSize, 0 );
- DrawCharacter( kCharacterStage+1, &numberRect );
-
- if( level < 10 )
- {
- OffsetMRect( &numberRect, kNumberHorizSize, 0 );
- DrawCharacter( level + '0', &numberRect );
- }
- else
- {
- OffsetMRect( &numberRect, kNumberHorizSize*3/4, 0 );
- DrawCharacter( (level / 10) + '0', &numberRect );
- OffsetMRect( &numberRect, kNumberHorizSize, 0 );
- DrawCharacter( (level % 10) + '0', &numberRect );
- }
-
- SDLU_BlitFrontSurface( levelSurface, &sourceSDLRect, &destSDLRect );
-
- SDLU_ReleaseSurface( levelSurface );
- SDL_FreeSurface( levelSurface );
-
- break;
- }
-}
-
-void InitGame( int player1, int player2 )
-{
- playerWindowVisible[0] = true;
- nextWindowVisible[0] = true;
- scoreWindowVisible[0] = true;
- grayMonitorVisible[0] = true;
-
- if( player2 == kNobodyControl )
- {
- playerWindowVisible[1] = false;
- nextWindowVisible[1] = false;
- scoreWindowVisible[1] = false;
- grayMonitorVisible[1] = false;
-
- CenterRectOnScreen( &playerWindowRect[0], 0.5, 0.5 );
- CenterRectOnScreen( &scoreWindowRect[0], 0.5, 0.89 );
- CenterRectOnScreen( &grayMonitorRect[0], 0.5, 0.11 );
- CenterRectOnScreen( &nextWindowRect[0], 0.3, 0.25 );
-
- CenterRectOnScreen( &stageWindowRect, 0.3, 0.65 );
- CenterRectOnScreen( &opponentWindowRect, 0.3, 0.5 );
- }
- else
- {
- playerWindowVisible[1] = true;
- nextWindowVisible[1] = true;
- scoreWindowVisible[1] = true;
- grayMonitorVisible[1] = true;
-
- CenterRectOnScreen( &playerWindowRect[0], kLeftPlayerWindowCenter, 0.5 );
- CenterRectOnScreen( &scoreWindowRect[0], kLeftPlayerWindowCenter, 0.89 );
- CenterRectOnScreen( &grayMonitorRect[0], kLeftPlayerWindowCenter, 0.11 );
- CenterRectOnScreen( &nextWindowRect[0], 0.46, 0.25 );
-
- CenterRectOnScreen( &playerWindowRect[1], kRightPlayerWindowCenter, 0.5 );
- CenterRectOnScreen( &scoreWindowRect[1], kRightPlayerWindowCenter, 0.89 );
- CenterRectOnScreen( &grayMonitorRect[1], kRightPlayerWindowCenter, 0.11 );
- CenterRectOnScreen( &nextWindowRect[1], 0.54, 0.25 );
-
- CenterRectOnScreen( &stageWindowRect, 0.5, 0.65 );
- CenterRectOnScreen( &opponentWindowRect, 0.5, 0.5 );
- }
-
- // In widescreen mode, move score/gray windows closer to the playfield
- // so they fit in the cropped screen.
- ResetWidescreenLayout();
-
- nextWindowVisible[0] = ( player1 == kAutoControl )? false: true;
-
- players = (player1 == kPlayerControl) + (player2 == kPlayerControl);
-
- if( players < 2 )
- {
- difficulty[0] = difficulty[1] = kHardLevel;
- }
-
- control[0] = player1;
- control[1] = player2;
-
- score[0] = score[1] = displayedScore[0] = displayedScore[1] = 0;
- roundStartScore[0] = roundStartScore[1] = 0;
-
- level = 1;
- credits = (player2 == kNobodyControl)? 1: 5;
-}
-
-void ResetWidescreenLayout()
-{
- int miniWindowOffset = widescreen ? 4 : 16;
-
- for (int i = 0; i < 2; i++)
- {
- grayMonitorRect[i].top = playerWindowRect[i].top - 32 - miniWindowOffset;
- grayMonitorRect[i].bottom = playerWindowRect[i].top - miniWindowOffset;
- scoreWindowRect[i].top = playerWindowRect[i].bottom + miniWindowOffset;
- scoreWindowRect[i].bottom = playerWindowRect[i].bottom + 16 + miniWindowOffset;
- }
-}
-
-MBoolean InitCharacter( int player, int level )
-{
- const Character characterList[] = {
- { -1 }, // no zero'th character
- { 0, 3, 1, { 8, 8, 8, 8, 8, 8 }, 13, 9, 0, 25, { 0, _15TO8_8_8(0), 0, 0, _15TO8_8_8(0), 0 }, true },
- { 1, 6, 2, { 10, 9, 8, 8, 9, 10 }, 12, 7, 1, 20, { 0, _15TO8_8_8(223), 7, 0, _15TO8_8_8(0), 0 }, true },
- { 2, 9, 3, { 7, 7, 7, 11, 7, 7 }, 10, 6, 2, 17, { 0, _15TO8_8_8(0), 0, 0, _15TO8_8_8(0), 0 }, false },
- { 3, 12, 4, { 11, 10, 9, 8, 7, 6 }, 8, 5, 3, 13, { 0, _15TO8_8_8(32767), 4, 0, _15TO8_8_8(16912), 4 }, false },
- { 4, 15, 0, { 5, 9, 10, 10, 9, 5 }, 7, 4, 4, 10, { 0, _15TO8_8_8(32767), 1, 0, _15TO8_8_8(0), 0 }, false },
- { 5, 17, 1, { 4, 7, 11, 11, 6, 3 }, 7, 2, 5, 8, { 0, _15TO8_8_8(14835), 8, 0, _15TO8_8_8(0), 0 }, false },
- { 6, 18, 2, { 7, 9, 10, 10, 9, 7 }, 6, 4, 6, 7, { 0, _15TO8_8_8(0), 0, 0, _15TO8_8_8(0), 0 }, false },
- { 7, 20, 3, { 5, 10, 10, 10, 10, 5 }, 5, 3, 7, 5, { 0, _15TO8_8_8(9696), 2, 0, _15TO8_8_8(21151), 3 }, false },
- { 8, 21, 4, { 11, 11, 10, 10, 9, 9 }, 4, 3, 8, 5, { 0, _15TO8_8_8(32738), 5, 0, _15TO8_8_8(0), 0 }, false },
- { 9, 22, 0, { 11, 7, 11, 7, 11, 7 }, 3, 1, 9, 4, { 0, _15TO8_8_8(32356), 5, 0, _15TO8_8_8(17392), 3 }, false },
- { 10, 23, 1, { 11, 11, 11, 11, 11, 11 }, 2, 1, 10, 2, { 0, _15TO8_8_8(6337), 1, 0, _15TO8_8_8(0), 0 }, false },
- { 11, 24, 2, { 11, 11, 11, 11, 11, 11 }, 2, 1, 11, 2, { 1, _15TO8_8_8(32767), 7, 0, _15TO8_8_8(0), 0 }, false },
- { -1 }, // skip
- { 13, 24, 1, { 11, 11, 11, 11, 11, 11 }, 10, 5, 0, 30, { 0, _15TO8_8_8(0), 0, 0, _15TO8_8_8(0), 0 }, true }
- };
-
- character[player] = characterList[level];
- return (character[player].picture != -1);
-}
-
-void PrepareStageGraphics( int type )
-{
- int player;
-
- MRect blobBoard = { 0, 0, kGridDown * kBlobVertSize, kGridAcross * kBlobHorizSize };
-
- backgroundID = type * 100;
-
- DrawPICTInSurface( boardSurface[0], picBoard + backgroundID );
-
- // NOTE: Many levels have no right-side board, so we copy the left
- // side over to the right side. This way, if DrawPICTInSurface flunks,
- // we still have a valid picture.
-
- SDLU_BlitSurface( boardSurface[0], &boardSurface[0]->clip_rect,
- boardSurface[1], &boardSurface[1]->clip_rect );
-
- DrawPICTInSurface( boardSurface[1], picBoardRight + backgroundID );
-
- DrawPICTInSurface( backdropSurface, picBackdrop + backgroundID );
-
- DrawPICTInSurface( nextSurface, picNext + backgroundID );
-
- for( player=0; player<=1; player++ )
- {
- SDLU_AcquireSurface( playerSurface[player] );
- SurfaceDrawBoard( player, &blobBoard );
- SDLU_ReleaseSurface( playerSurface[player] );
-
- CleanSpriteArea( player, &blobBoard );
- }
-
- BeginOpponent( type );
-
- RedrawBoardContents( 0 );
- RedrawBoardContents( 1 );
-
- RefreshAll( );
-
- backdropTicks = MTickCount( );
- backdropFrame = 0;
-}
-
-void BeginRound( MBoolean changeMusic )
-{
- int player, count, count2;
-
- InitGrays( );
- InitPotentialCombos( );
-
- switch( players )
- {
- case 0:
- case 1:
- if( InitCharacter( 1, level ) )
- {
- score[1] = roundStartScore[1] = displayedScore[1] = 0;
- character[0] = character[1];
- character[0].zapStyle = RandomBefore(5);
- }
- else
- {
- TotalVictory( );
- return;
- }
-
- if( control[1] == kNobodyControl )
- {
- InitRandom( 3 );
- }
- else
- {
- InitRandom( 5 );
- }
- break;
-
- case 2:
- score[0] = score[1] = roundStartScore[0] = roundStartScore[1] = displayedScore[0] = displayedScore[1] = 0;
-
- InitRandom( 5 );
-
- SelectRandomLevel( );
- InitCharacter( 0, level );
-
- SelectRandomLevel( );
- InitCharacter( 1, level );
-
- character[0].hints = (difficulty[0] == kEasyLevel) || (difficulty[0] == kMediumLevel);
- character[1].hints = (difficulty[1] == kEasyLevel) || (difficulty[1] == kMediumLevel);
- break;
- }
-
- for( player=0; player<=1; player++ )
- {
- for( count=0; count<kGridAcross; count++ )
- {
- grays[player][count] = 0;
-
- for( count2=0; count2<kGridDown; count2++ )
- {
- grid[player][count][count2] = kEmpty;
- suction[player][count][count2] = kNoSuction;
- charred[player][count][count2] = kNoCharring;
- glow[player][count][count2] = false;
- }
- }
-
- nextA[player] = GetPiece( player );
- nextB[player] = GetPiece( player );
- nextM[player] = false;
- nextG[player] = false;
-
- halfway[player] = false;
-
- unallocatedGrays[player] = 0;
- anim[player] = 0;
- lockGrays[player] = 0;
- roundStartScore[player] = score[player];
-
- RedrawBoardContents(player);
-
- if( control[player] != kNobodyControl )
- {
- role[player] = kWaitForRetrieval;
- }
- else
- {
- role[player] = kIdlePlayer;
- }
- }
-
- PrepareStageGraphics( character[1].picture );
- if( changeMusic ) ChooseMusic( character[1].music );
-
- blobTime[0] = blobTime[1] =
- boredTime[0] = boredTime[1] =
- hintTime[0] = hintTime[1] =
- timeAI[0] = timeAI[1] =
- fadeCharTime[0] = fadeCharTime[1] =
- messageTime = startTime =
- blinkTime[0] = blinkTime[1] = GameTickCount( );
-
- blinkTime[1] += 60;
-
- if( players == 2 )
- InitDifficulty( );
-
- SDLU_Present();
-}
-
-void IncrementLevel( void )
-{
- level++;
-}
-
-void SelectRandomLevel( void )
-{
- level = RandomBefore(kLevels) + 1;
-}
-
-void InitDifficulty( )
-{
- MRect blobBoard = { 0, 0, kGridDown * kBlobVertSize, kGridAcross * kBlobHorizSize };
- int player;
- const int selectionRow = 5;
- int count;
- MRect blobRect;
-
- for( player=0; player<=1; player++ )
- {
- // Set up variables
- role[player] = kChooseDifficulty;
- colorA[player] = RandomBefore(kBlobTypes)+1;
- colorB[player] = kEmpty;
- switch( difficulty[player] )
- {
- case kEasyLevel: blobX[player] = 1; break;
- case kMediumLevel: blobX[player] = 2; break;
- case kHardLevel: blobX[player] = 3; break;
- case kUltraLevel: blobX[player] = 4; break;
- }
-
- blobY[player] = selectionRow;
- blobR[player] = upRotate;
- blobTime[player] = GameTickCount( ) + (60*8);
- animTime[player] = GameTickCount( );
- shadowDepth[player] = kBlobShadowDepth;
- magic[player] = false;
- grenade[player] = false;
-
- DrawPICTInSurface( boardSurface[player], picSelectDifficulty + backgroundID );
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- SurfaceDrawBoard( player, &blobBoard );
-
- grid[player][0][selectionRow] = kGray;
- suction[player][0][selectionRow] = kEasyGray;
- charred[player][0][selectionRow] = kNoCharring;
- CalcBlobRect( 0, selectionRow, &blobRect );
- SurfaceDrawBlob( player, &blobRect, kGray, kEasyGray, kNoCharring );
-
- grid[player][kGridAcross-1][selectionRow] = kGray;
- suction[player][kGridAcross-1][selectionRow] = kHardGray;
- charred[player][kGridAcross-1][selectionRow] = kNoCharring;
- CalcBlobRect( kGridAcross-1, selectionRow, &blobRect );
- SurfaceDrawBlob( player, &blobRect, kGray, kHardGray, kNoCharring );
-
- CalcBlobRect( 1, selectionRow, &blobRect );
- blobRect.top -= 4; blobRect.bottom += 4;
- blobRect.left += 4; blobRect.right -= 4;
- for( count=1; count<=4; count++ )
- {
- DrawCharacter( count + '0', &blobRect );
- OffsetMRect( &blobRect, kBlobHorizSize, 0 );
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-
- DrawSpriteBlobs( player, kNoSuction );
- CleanSpriteArea( player, &blobBoard );
- }
-}
-
-void ChooseDifficulty( int player )
-{
- MRect blobBoard = { 0, 0, kGridDown * kBlobVertSize, kGridAcross * kBlobHorizSize };
- const int selectionRow = 5;
- const int difficultyMap[kGridAcross] = {kEasyLevel, kEasyLevel, kMediumLevel, kHardLevel, kUltraLevel, kUltraLevel};
- const int fallingSpeed[kGridAcross] = {0, 15, 9, 7, 4, 0};
- const int startGrays[kGridAcross] = {0, 0, 0, 10, 20, 0};
- const int difficultyFrame[] = { kNoSuction, blobBlinkAnimation, blobBlinkAnimation,
- blobJiggleAnimation, blobCryAnimation, kNoSuction };
- int oldX = blobX[player];
-
- PlayerControl( player );
- if( blobX[player] != oldX ) anim[player] = 0;
-
- UpdateTweak( player, difficultyFrame[blobX[player]] );
-
- if( GameTickCount( ) >= blobTime[player] )
- {
- if( player == 1 && PICTExists( picBoardRight + backgroundID ) )
- {
- DrawPICTInSurface( boardSurface[player], picBoardRight + backgroundID );
- }
- else
- {
- DrawPICTInSurface( boardSurface[player], picBoard + backgroundID );
- }
-
- SDLU_AcquireSurface( playerSurface[player] );
- SurfaceDrawBoard( player, &blobBoard );
- SDLU_ReleaseSurface( playerSurface[player] );
-
- CleanSpriteArea( player, &blobBoard );
-
- grid[player][0][selectionRow] = kEmpty;
- grid[player][5][selectionRow] = kEmpty;
-
- suction[player][0][selectionRow] = kNoSuction;
- suction[player][5][selectionRow] = kNoSuction;
-
- difficulty[player] = difficultyMap[ blobX[player] ];
- character[player].dropSpeed = fallingSpeed[ blobX[player] ];
- unallocatedGrays[player] = lockGrays[player] = startGrays[blobX[player]];
- character[player].hints = (startGrays[blobX[player]] == 0);
- role[player] = kWaitingToStart;
-
- PlayStereoFrequency( player, kPause, player );
- }
-}
-
-const char *gameCredits[][6] =
-{
- { "Programming", "John Stiles", "", "", "", "" },
- { "Artwork", "Kate Davis", "Leanne Stiles", "Arnauld de la Grandiere", "Bob Frasure", "Ryan Bliss" },
- { "Music", "Leanne Stiles", "fmod", "Lizardking", "Armadon, Explizit", "Leviathan, Nemesis" },
- { "Music", "Jester, Pygmy", "Siren", "Sirrus", "Scaven, FC", "Spring" },
- { "Music", "Timewalker", "Jason, Silents", "Chromatic Dragon", "Ng Pei Sin", "" },
- { "Source Port", "Iliyas Jorio", "github.com/jorio/candycrisis", "", "", "" },
- { "Special Thanks", "Sam Lantinga", "Carey Lening", "modarchive.com", "digitalblasphemy.com", "" },
- { "", "", "", "", "", "" }
-};
-
-void SharewareVictory( void )
-{
- SkittlesFontPtr textFont, titleFont;
- SDL_Surface* backBuffer;
- SDL_Surface* frontBuffer;
- SDL_Rect creditSrcSDLRect, bufferSrcSDLRect, bufferDstSDLRect;
- MRect creditSrcRect = { 0, 0, 369, 150 };
- MRect bufferSrcRect = { 0, 50, 480, 350 };
- MRect bufferDstRect = { 0, 0, 480, 300 };
- MPoint dPoint = { 450, 50 }, lPoint, cPoint;
- int scroll, x, y;
- MTicks ticks;
- const char* text;
- int thisFade;
- const char fade[120] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0
- 1, 2, 3, 4, 5, 6, 7, 8, 9,10, //1
- 11,12,13,14,15,16,17,18,19,20, //2
- 20,20,20,20,20,20,20,20,20,20, //3
- 20,20,20,20,20,20,20,20,20,20, //4
- 20,20,20,20,20,20,20,20,20,20, //5
- 20,20,20,20,20,20,20,20,20,20, //6
- 20,20,20,20,20,20,20,20,20,20, //7
- 20,20,20,20,20,20,20,20,20,20, //8
- 20,19,18,17,16,15,14,13,12,11, //9
- 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, //10
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 //11
- };
-
- titleFont = GetFont( picFont );
- textFont = GetFont( picTinyFont );
-
- SDLU_MRectToSDLRect( &creditSrcRect, &creditSrcSDLRect );
- SDLU_MRectToSDLRect( &bufferSrcRect, &bufferSrcSDLRect );
- SDLU_MRectToSDLRect( &bufferDstRect, &bufferDstSDLRect );
-
- DrawPICTInSurface( g_frontSurface, picSharewareVictory );
- SDLU_Present();
-
- backBuffer = SDLU_InitSurface( &bufferDstSDLRect, 32 );
-
- SDLU_BlitSurface( g_frontSurface, &bufferSrcSDLRect,
- backBuffer, &bufferDstSDLRect );
-
- frontBuffer = SDLU_InitSurface( &bufferDstSDLRect, 32 );
-
- QuickFadeIn( NULL );
-
- ChooseMusic( 12 );
-
- ticks = MTickCount();
- for( scroll=0; scroll<1500; scroll++ )
- {
- SDLU_AcquireSurface( frontBuffer );
-
- SDLU_BlitSurface( backBuffer, &bufferDstSDLRect,
- frontBuffer, &bufferDstSDLRect );
-
- ticks += 3;
- lPoint = dPoint;
- for( y=0; y<8; y++ )
- {
- if( y != 3 && y != 4 )
- {
- cPoint.v = lPoint.v + 25;
- cPoint.h = lPoint.h;
- if( cPoint.v > 480 ) break;
-
- if( cPoint.v > 0 )
- {
- text = gameCredits[y][0];
- thisFade = fade[cPoint.v >> 2];
-
- while( *text )
- {
- SurfaceBlitWeightedCharacter( titleFont, *text++, &cPoint, 255, 255, 0, _5TO8(thisFade) );
- }
- }
-
- lPoint.v += 50;
- }
-
- for( x=1; x<6; x++ )
- {
- if( gameCredits[y][x][0] )
- {
- cPoint.v = lPoint.v;
- cPoint.h = lPoint.h + 20;
- if( cPoint.v > 480 ) break;
-
- if( cPoint.v > 0 )
- {
- text = gameCredits[y][x];
- thisFade = fade[cPoint.v >> 2];
-
- while( *text )
- {
- SurfaceBlitWeightedCharacter( textFont, *text++, &cPoint, 255, 255, 0, _5TO8(thisFade) );
- }
- }
-
- lPoint.v += 20;
- }
- }
- }
-
- SDLU_ReleaseSurface( frontBuffer );
-
- dPoint.v--;
-
- SDLU_BlitFrontSurface( frontBuffer, &bufferDstSDLRect, &bufferSrcSDLRect );
- SDLU_Present();
-
- do
- {
- if( SDLU_Button() ) goto out;
- SDLU_Yield();
- }
- while( ticks >= MTickCount() );
- }
-
- do
- {
- SDLU_Yield();
- }
- while( !AnyKeyIsPressed( ) && !SDLU_Button() );
-
-out:
- QuickFadeOut( NULL );
-
- SDL_FreeSurface( backBuffer );
- SDL_FreeSurface( frontBuffer );
-}
-
-void RegisteredVictory( void )
-{
- SkittlesFontPtr textFont, titleFont, bubbleFont;
- SDL_Surface* backBuffer;
- SDL_Surface* frontBuffer;
- MPoint dPoint[] = { { 230, 340 }, { 230, 30 }, { 230, 30 }, { 30, 30 }, { 30, 340 }, { 230, 340 }, { 230, 30 } };
- MPoint bubblePoint, textPoint, shadowPoint;
- MPoint setPoint[7][6];
- MPoint msgSetPoint[7][2];
- MTicks ticks;
- int vertScroll, picture, weight, line, minimum;
- int scrollDir[] = {1, -1, 1, -1, 1, -1, -1};
- int spacing[] = {40, 19, 19, 19, 23, 19, 23 };
- const char* text;
- SDL_Rect fullSDLRect = { 0, 0, 640, 480 };
- SDL_Rect highSDLRect = { 0, 0, 640, 480 };
- SDL_Rect lowSDLRect = { 0, 250, 640, 480 };
- SDL_Rect backBufferSDLRect = { 0, 0, 640, 730 };
- SDL_Rect scrollSDLRect;
-
- const char *messages[7][2] =
- {
- { "Congratulations!", "" },
- { "You've managed to vaporize all", "of the rampaging candies!" },
- { "Your quick thinking and sharp", "reflexes have saved the day." },
- { "", "" },
- { "", "" },
- { "", "" },
- { "Thanks for playing Candy Crisis!", "" },
- };
-
- // In widescreen mode, move vertical text positions closer to the center
- if (widescreen) {
- for (auto& dp : dPoint) {
- if (dp.v >= 130) {
- dp.v -= 20;
- } else {
- dp.v += 20;
- }
- }
- }
-
- textFont = GetFont( picTinyFont );
- titleFont = GetFont( picHiScoreFont );
- bubbleFont = GetFont( picBubbleFont );
-
- ChooseMusic( 14 );
-
- for( picture=0; picture<7; picture++ )
- {
- for( line=0; line<2; line++ )
- {
- if (dPoint[picture].v >= 130) {
- msgSetPoint[picture][line].v = (widescreen? 120: 100) + line * 30;
- } else {
- msgSetPoint[picture][line].v = (widescreen? 380: 300) + line * 30;
- }
- msgSetPoint[picture][line].h = 320 - (GetTextWidth( titleFont, messages[picture][line] ) / 2);
- }
-
- for( line=0; line<6; line++ )
- {
- SkittlesFontPtr font;
-
- if( line == 0 )
- {
- font = titleFont;
- textPoint.v = 45;
- }
- else
- {
- font = textFont;
- textPoint.v = 65 + (spacing[picture] * line);
- }
-
- textPoint.h = (bubbleFont->width['*'] - GetTextWidth( font, gameCredits[picture][line] )) / 2;
-
- setPoint[picture][line].v = dPoint[picture].v + textPoint.v;
- setPoint[picture][line].h = dPoint[picture].h + textPoint.h;
- }
-
- minimum = 640;
- for( line=1; line<6; line++ )
- {
- if( setPoint[picture][line].h < minimum ) minimum = setPoint[picture][line].h;
- }
-
- for( line=1; line<6; line++ )
- {
- setPoint[picture][line].h = minimum;
- }
- }
-
- backBuffer = SDLU_InitSurface( &backBufferSDLRect, 32 );
- frontBuffer = SDLU_InitSurface( &fullSDLRect, 32 );
-
- for( picture = 0; picture<7; picture++ )
- {
- scrollSDLRect = ( scrollDir[picture] > 0 )? highSDLRect: lowSDLRect;
-
- DrawPICTInSurface( backBuffer, picture + picVictory1 );
-
- SDLU_BlitFrontSurface( backBuffer, &scrollSDLRect, &fullSDLRect );
- SDLU_Present();
-
- QuickFadeIn( NULL );
-
- ticks = MTickCount();
- for( vertScroll = 0; vertScroll < 250; vertScroll++ )
- {
- SDLU_AcquireSurface( frontBuffer );
-
- SDLU_BlitSurface( backBuffer, &scrollSDLRect,
- frontBuffer, &fullSDLRect );
-
- weight = vertScroll - 20;
- for( line=0; line<2; line++ )
- {
- textPoint = msgSetPoint[picture][line];
- shadowPoint.v = textPoint.v + 1;
- shadowPoint.h = textPoint.h + 1;
-
- text = messages[picture][line];
-
- while( *text && weight > 0 )
- {
- int fixedWeight = (weight > 31)? 31: weight;
-
- SurfaceBlitWeightedCharacter( titleFont, *text, &shadowPoint, 0, 0, 0, _5TO8(fixedWeight) );
- SurfaceBlitWeightedCharacter( titleFont, *text, &textPoint, 255, 255, 255, _5TO8(fixedWeight) );
- weight--;
- text++;
- }
- }
-
- bubblePoint = dPoint[picture];
- weight = ( vertScroll <= 210 )? vertScroll - 10: 241 - vertScroll;
- if( weight < 0 ) weight = 0;
- if( weight > 31 ) weight = 31;
-
- if( weight > 0 )
- {
- int bubbleWeight = (weight+1)>>1;
-
- SurfaceBlitWeightedCharacter( bubbleFont, '*', &bubblePoint, 255, 255, 255, _5TO8(bubbleWeight) );
-
- for( line=0; line<6; line++ )
- {
- SkittlesFontPtr font = (line == 0)? titleFont: textFont;
-
- textPoint = setPoint[picture][line];
- text = gameCredits[picture][line];
-
- while( *text )
- {
- SurfaceBlitWeightedCharacter( font, *text++, &textPoint, 0, 0, 0, _5TO8(weight) );
- }
- }
- }
-
- SDLU_ReleaseSurface( frontBuffer );
-
- SDLU_BlitFrontSurface( frontBuffer, &fullSDLRect, &fullSDLRect );
- SDLU_Present();
-
- scrollSDLRect.y += scrollDir[picture];
-
- ticks += 4;
- do
- {
- if( SDLU_Button() ) vertScroll = 250;
- SDLU_Yield();
- }
- while( ticks >= MTickCount() );
- }
-
- QuickFadeOut( NULL );
- }
-
- SDL_FreeSurface( backBuffer );
- SDL_FreeSurface( frontBuffer );
-}
-
-void TotalVictory( void )
-{
- AddHiscore( score[0] );
- QuickFadeOut( NULL );
-
- DoFullRepaint = NoPaint;
-
- RegisteredVictory( );
-
- showStartMenu = true;
-}
binary files /dev/null b/src/main.c differ
binary files a/src/main.cpp /dev/null differ
--- a/src/main.h
+++ b/src/main.h
@@ -34,10 +34,10 @@
void WaitForRegainFocus();
-struct KeyList
+typedef struct KeyList
{
short left, right, drop, rotate;
-};
+} KeyList;
#define kGridAcross 6
@@ -238,9 +238,9 @@
#define kLastBlob kBlob7
#define kBlobTypes (kLastBlob - kFirstBlob + 1)
-constexpr double pi = 3.14159265358979323846264338327950288;
+#define kPi 3.14159265358979323846264338327950288
-#define arrsize(x) int(sizeof((x)) / sizeof((x)[0]))
+#define arrsize(x) ( (int)(sizeof((x)) / sizeof((x)[0])) )
extern SDL_Renderer* g_renderer;
extern SDL_Window* g_window;
--- /dev/null
+++ b/src/moving.c
@@ -1,0 +1,208 @@
+// moving.c
+
+#include "main.h"
+#include "moving.h"
+#include "players.h"
+#include "graphics.h"
+#include "soundfx.h"
+#include "tweak.h"
+#include "gameticks.h"
+#include "level.h"
+
+void CalcSecondBlobOffset( int player, int *x, int *y )
+{
+ *x = *y = 0;
+
+ switch( blobR[player] )
+ {
+ case rightRotate:
+ *x = 1;
+ break;
+
+ case downRotate:
+ *y = 1;
+ break;
+
+ case leftRotate:
+ *x = -1;
+ break;
+
+ case upRotate:
+ *y = -1;
+ break;
+ }
+}
+
+MBoolean CanGoLeft( int player )
+{
+ return CanMoveDirection( player, -1, halfway[player]? 1: 0 );
+}
+
+void GoLeft( int player )
+{
+ EraseSpriteBlobs( player );
+ blobX[player]--;
+ StartTweak( player, -1, 0, 0 );
+ DrawSpriteBlobs( player, kNoSuction );
+
+ PlayStereo( player, kShift );
+}
+
+MBoolean CanGoRight( int player )
+{
+ return CanMoveDirection( player, 1, halfway[player]? 1: 0 );
+}
+
+void GoRight( int player )
+{
+ EraseSpriteBlobs( player );
+ blobX[player]++;
+ StartTweak( player, 1, 0, 0 );
+ DrawSpriteBlobs( player, kNoSuction );
+
+ PlayStereo( player, kShift );
+}
+
+MBoolean CanFall( int player )
+{
+ return CanMoveDirection( player, 0, 1 );
+}
+
+MBoolean CanMoveDirection( int player, int dirX, int dirY )
+{
+ int currentX = blobX[player], currentY = blobY[player], x, y;
+
+ currentX += dirX;
+ currentY += dirY;
+
+ if( currentX < 0 || currentX >= kGridAcross || currentY >= kGridDown )
+ return false;
+
+ if( currentY >= 0 )
+ if( grid[player][currentX][currentY] != kEmpty )
+ return false;
+
+ CalcSecondBlobOffset( player, &x, &y );
+
+ currentX += x;
+ currentY += y;
+
+ if( currentX < 0 || currentX >= kGridAcross || currentY >= kGridDown )
+ return false;
+
+ if( currentY >= 0 )
+ if( grid[player][currentX][currentY] != kEmpty )
+ return false;
+
+ return true;
+}
+
+void DoFall( int player )
+{
+ EraseSpriteBlobs( player );
+
+ if( halfway[player] )
+ blobY[player]++;
+ halfway[player] = !halfway[player];
+
+ StartTweak( player, 0, 0, 1 );
+
+ DrawSpriteBlobs( player, kNoSuction );
+}
+
+MBoolean CanRotate( int player )
+{
+ if( role[player] == kChooseDifficulty ) return false;
+
+ if( grenade[player] ) return false;
+
+ return true;
+
+}
+
+void DoRotate( int player )
+{
+ MBoolean possible;
+
+ EraseSpriteBlobs( player );
+
+ blobR[player] = ( blobR[player] + 1 ) % 4;
+ possible = CanMoveDirection( player, 0, halfway[player]? 1: 0 );
+ StartTweak( player, 0, 1, 0 ); // only rotates clockwise
+
+ if( !possible )
+ {
+ if( blobR[player] == downRotate )
+ {
+ if( halfway[player] )
+ halfway[player] = false;
+ else
+ blobY[player]--;
+
+ if( ++blobSpin[player] >= 4 )
+ {
+ blobTime[player] = animTime[player] = GameTickCount( );
+ role[player] = kLockdownBlobs;
+ anim[player] = 0;
+ PlayStereoFrequency( player, kPlace, player );
+ }
+ }
+
+ if( blobR[player] == leftRotate )
+ {
+ if( CanGoRight(player) )
+ GoRight( player );
+ else
+ {
+ blobR[player]++;
+ StartTweak( player, 0, 2, 0 );
+ }
+ }
+
+ if( blobR[player] == rightRotate )
+ {
+ if( CanGoLeft(player) )
+ GoLeft( player );
+ else
+ {
+ blobR[player]++;
+ StartTweak( player, 0, 2, 0 );
+
+ if( !CanMoveDirection( player, 0, halfway[player]? 1: 0 ) )
+ {
+ if( halfway[player] )
+ halfway[player] = false;
+ else
+ blobY[player]--;
+
+ if( ++blobSpin[player] >= 4 )
+ {
+ blobTime[player] = animTime[player] = GameTickCount( );
+ role[player] = kLockdownBlobs;
+ anim[player] = 0;
+ PlayStereoFrequency( player, kPlace, player );
+ }
+ }
+ }
+ }
+ }
+
+ DrawSpriteBlobs( player, kNoSuction );
+
+ PlayStereo( player, kRotate );
+}
+
+void DoDrop( int player )
+{
+ dropping[player] = true;
+
+ if( role[player] != kJiggleBlobs &&
+ role[player] != kFastJiggleBlobs &&
+ role[player] != kLockdownBlobs )
+ blobTime[player] = GameTickCount( );
+}
+
+void StopDrop( int player )
+{
+ dropping[player] = false;
+}
--- a/src/moving.cpp
+++ /dev/null
@@ -1,208 +1,0 @@
-// moving.c
-
-#include "main.h"
-#include "moving.h"
-#include "players.h"
-#include "graphics.h"
-#include "soundfx.h"
-#include "tweak.h"
-#include "gameticks.h"
-#include "level.h"
-
-void CalcSecondBlobOffset( int player, int *x, int *y )
-{
- *x = *y = 0;
-
- switch( blobR[player] )
- {
- case rightRotate:
- *x = 1;
- break;
-
- case downRotate:
- *y = 1;
- break;
-
- case leftRotate:
- *x = -1;
- break;
-
- case upRotate:
- *y = -1;
- break;
- }
-}
-
-MBoolean CanGoLeft( int player )
-{
- return CanMoveDirection( player, -1, halfway[player]? 1: 0 );
-}
-
-void GoLeft( int player )
-{
- EraseSpriteBlobs( player );
- blobX[player]--;
- StartTweak( player, -1, 0, 0 );
- DrawSpriteBlobs( player, kNoSuction );
-
- PlayStereo( player, kShift );
-}
-
-MBoolean CanGoRight( int player )
-{
- return CanMoveDirection( player, 1, halfway[player]? 1: 0 );
-}
-
-void GoRight( int player )
-{
- EraseSpriteBlobs( player );
- blobX[player]++;
- StartTweak( player, 1, 0, 0 );
- DrawSpriteBlobs( player, kNoSuction );
-
- PlayStereo( player, kShift );
-}
-
-MBoolean CanFall( int player )
-{
- return CanMoveDirection( player, 0, 1 );
-}
-
-MBoolean CanMoveDirection( int player, int dirX, int dirY )
-{
- int currentX = blobX[player], currentY = blobY[player], x, y;
-
- currentX += dirX;
- currentY += dirY;
-
- if( currentX < 0 || currentX >= kGridAcross || currentY >= kGridDown )
- return false;
-
- if( currentY >= 0 )
- if( grid[player][currentX][currentY] != kEmpty )
- return false;
-
- CalcSecondBlobOffset( player, &x, &y );
-
- currentX += x;
- currentY += y;
-
- if( currentX < 0 || currentX >= kGridAcross || currentY >= kGridDown )
- return false;
-
- if( currentY >= 0 )
- if( grid[player][currentX][currentY] != kEmpty )
- return false;
-
- return true;
-}
-
-void DoFall( int player )
-{
- EraseSpriteBlobs( player );
-
- if( halfway[player] )
- blobY[player]++;
- halfway[player] = !halfway[player];
-
- StartTweak( player, 0, 0, 1 );
-
- DrawSpriteBlobs( player, kNoSuction );
-}
-
-MBoolean CanRotate( int player )
-{
- if( role[player] == kChooseDifficulty ) return false;
-
- if( grenade[player] ) return false;
-
- return true;
-
-}
-
-void DoRotate( int player )
-{
- MBoolean possible;
-
- EraseSpriteBlobs( player );
-
- blobR[player] = ( blobR[player] + 1 ) % 4;
- possible = CanMoveDirection( player, 0, halfway[player]? 1: 0 );
- StartTweak( player, 0, 1, 0 ); // only rotates clockwise
-
- if( !possible )
- {
- if( blobR[player] == downRotate )
- {
- if( halfway[player] )
- halfway[player] = false;
- else
- blobY[player]--;
-
- if( ++blobSpin[player] >= 4 )
- {
- blobTime[player] = animTime[player] = GameTickCount( );
- role[player] = kLockdownBlobs;
- anim[player] = 0;
- PlayStereoFrequency( player, kPlace, player );
- }
- }
-
- if( blobR[player] == leftRotate )
- {
- if( CanGoRight(player) )
- GoRight( player );
- else
- {
- blobR[player]++;
- StartTweak( player, 0, 2, 0 );
- }
- }
-
- if( blobR[player] == rightRotate )
- {
- if( CanGoLeft(player) )
- GoLeft( player );
- else
- {
- blobR[player]++;
- StartTweak( player, 0, 2, 0 );
-
- if( !CanMoveDirection( player, 0, halfway[player]? 1: 0 ) )
- {
- if( halfway[player] )
- halfway[player] = false;
- else
- blobY[player]--;
-
- if( ++blobSpin[player] >= 4 )
- {
- blobTime[player] = animTime[player] = GameTickCount( );
- role[player] = kLockdownBlobs;
- anim[player] = 0;
- PlayStereoFrequency( player, kPlace, player );
- }
- }
- }
- }
- }
-
- DrawSpriteBlobs( player, kNoSuction );
-
- PlayStereo( player, kRotate );
-}
-
-void DoDrop( int player )
-{
- dropping[player] = true;
-
- if( role[player] != kJiggleBlobs &&
- role[player] != kFastJiggleBlobs &&
- role[player] != kLockdownBlobs )
- blobTime[player] = GameTickCount( );
-}
-
-void StopDrop( int player )
-{
- dropping[player] = false;
-}
--- a/src/music.cpp
+++ b/src/music.cpp
@@ -4,6 +4,9 @@
#include <vector>
#include <fstream>
+extern "C"
+{
+
#include "main.h"
#include "music.h"
#include "gworld.h"
@@ -11,16 +14,21 @@
#include "soundfx.h"
#include "graphics.h"
+}
+
#include "support/ModStream.h"
const int k_noMusic = -1;
const int k_songs = 14;
+extern "C"
+{
MBoolean musicOn = true;
int musicSelection = k_noMusic;
static MBoolean s_musicFast = false;
int s_musicPaused = 0;
+}
static cmixer::ModStream* s_musicChannel = NULL;
--- /dev/null
+++ b/src/next.c
@@ -1,0 +1,208 @@
+// next.c
+
+#include "SDLU.h"
+
+#include "main.h"
+#include "next.h"
+#include "graphics.h"
+#include "gworld.h"
+#include "gameticks.h"
+#include "random.h"
+#include "blitter.h"
+#include "level.h"
+
+#define kJiggleFrames 8
+#define kPulling 10
+#define kPullingFrames 18
+
+SDL_Surface* nextSurface;
+SDL_Surface* nextDrawSurface;
+
+MRect nextWindowZRect, nextWindowRect[2];
+MBoolean nextWindowVisible[2] = {true, true};
+MTicks nextTime[2][2];
+int nextStage[2][2], pullA[2], pullB[2];
+
+void InitNext( void )
+{
+ const double windowLoc[] = {0.46, 0.54};
+ SDL_Rect sdlRect;
+
+ nextWindowZRect.top = nextWindowZRect.left = 0;
+ nextWindowZRect.bottom = 72; nextWindowZRect.right = 32;
+
+ nextWindowRect[0] = nextWindowRect[1] = nextWindowZRect;
+ CenterRectOnScreen( &nextWindowRect[0], windowLoc[0], 0.25 );
+ CenterRectOnScreen( &nextWindowRect[1], windowLoc[1], 0.25 );
+
+ nextSurface = LoadPICTAsSurface( picNext, 32 );
+
+ nextDrawSurface = SDLU_InitSurface( SDLU_MRectToSDLRect( &nextWindowZRect, &sdlRect ), 32 );
+}
+
+void RefreshNext( int player )
+{
+ nextStage[player][0] = 0;
+ nextStage[player][1] = 0;
+
+ nextTime[player][0] = GameTickCount( ) + RandomBefore( 60 );
+ nextTime[player][1] = GameTickCount( ) + RandomBefore( 60 );
+
+ ShowNext( player );
+}
+
+void PullNext( int player )
+{
+ pullA[player] = nextA[player];
+ pullB[player] = nextB[player];
+ nextStage[player][0] = kPulling;
+ nextTime[player][0] = GameTickCount( );
+}
+
+#define kNoDraw 999
+void ShowPull( int player )
+{
+ MRect srcRect;
+ int yank[8] = { 20, 18, 15, 8, -6, -26, -46, -66 };
+ int slide[8] = { kNoDraw, 66, 48, 36, 29, 26, 24, 23 };
+ int drawA, drawB, offset, count;
+ SDL_Rect sourceSDLRect, destSDLRect;
+
+ if( !nextWindowVisible[player] ) return;
+
+ SDLU_AcquireSurface( nextDrawSurface );
+
+ SDLU_BlitSurface( nextSurface, &nextSurface->clip_rect,
+ nextDrawSurface, &nextDrawSurface->clip_rect );
+
+ for( count=0; count<2; count++ )
+ {
+ offset = nextStage[player][0] - kPulling;
+
+ switch( count )
+ {
+ case 0: drawA = pullA[player]; drawB = pullB[player]; offset = yank[offset]; break;
+ case 1: drawA = nextA[player]; drawB = nextB[player]; offset = slide[offset]; break;
+ }
+
+ if( offset != kNoDraw )
+ {
+ MRect blobRect = { 0, 4, 0 + kBlobVertSize, 4 + kBlobHorizSize };
+ MRect shadowRect = { 4, 8, 4 + kBlobVertSize, 8 + kBlobHorizSize };
+
+ OffsetMRect( &blobRect, 0, offset );
+ OffsetMRect( &shadowRect, 0, offset );
+
+ SurfaceDrawShadow( &shadowRect, drawB, kNoSuction );
+
+ CalcBlobRect( kNoSuction, drawB-1, &srcRect );
+ SurfaceBlitBlob( &srcRect, &blobRect );
+
+ OffsetMRect( &blobRect, 0, kBlobVertSize );
+ OffsetMRect( &shadowRect, 0, kBlobVertSize );
+
+ SurfaceDrawShadow( &shadowRect, drawA, nextM[player]? kFlashDarkBlob: kNoSuction );
+
+ CalcBlobRect( nextM[player]? kFlashDarkBlob: kNoSuction, drawA-1, &srcRect );
+ SurfaceBlitBlob( &srcRect, &blobRect );
+ }
+ }
+
+ SDLU_ReleaseSurface( nextDrawSurface );
+
+ SDLU_BlitFrontSurface( nextDrawSurface,
+ SDLU_MRectToSDLRect( &nextWindowZRect, &sourceSDLRect ),
+ SDLU_MRectToSDLRect( &nextWindowRect[player], &destSDLRect ) );
+}
+
+void UpdateNext( int player )
+{
+ MBoolean changed = false;
+ int blob;
+
+ if( nextStage[player][0] >= kPulling )
+ {
+ if( GameTickCount() > nextTime[player][0] )
+ {
+ if( ++nextStage[player][0] >= kPullingFrames )
+ {
+ RefreshNext( player );
+ }
+ else
+ {
+ ShowPull( player );
+ nextTime[player][0]++;
+ }
+ }
+ }
+ else
+ {
+ for( blob=0; blob<2; blob++ )
+ {
+ if( GameTickCount() > nextTime[player][blob] )
+ {
+ if( ++nextStage[player][blob] >= kJiggleFrames )
+ {
+ nextStage[player][blob] = 0;
+ nextTime[player][blob] += 40 + RandomBefore( 80 );
+ }
+ else
+ {
+ nextTime[player][blob] += 2;
+ }
+
+ changed = true;
+ }
+ }
+
+ if( changed ) ShowNext( player );
+ }
+}
+
+void ShowNext( int player )
+{
+ int jiggle[kJiggleFrames] = { kNoSuction, kSquish, kNoSuction, kSquash,
+ kNoSuction, kSquish, kNoSuction, kSquash };
+ int nextFrame = kNoSuction;
+ MRect blobRect = { 22, 4, 22 + kBlobVertSize, 4 + kBlobHorizSize };
+ MRect shadowRect = { 26, 8, 26 + kBlobVertSize, 8 + kBlobHorizSize };
+ MRect srcRect;
+ SDL_Rect sourceSDLRect, destSDLRect;
+
+ if( !nextWindowVisible[player] ) return;
+
+ if( control[player] == kNobodyControl )
+ {
+ }
+ else
+ {
+ SDLU_AcquireSurface( nextDrawSurface );
+
+ SDLU_BlitSurface( nextSurface, &nextSurface->clip_rect,
+ nextDrawSurface, &nextDrawSurface->clip_rect );
+
+ nextFrame = nextG[player]? kNoSuction: jiggle[nextStage[player][0]];
+
+ SurfaceDrawShadow( &shadowRect, nextB[player], nextFrame );
+
+ CalcBlobRect( nextFrame, nextB[player]-1, &srcRect );
+ SurfaceBlitBlob( &srcRect, &blobRect );
+
+ OffsetMRect( &blobRect, 0, kBlobVertSize );
+ OffsetMRect( &shadowRect, 0, kBlobVertSize );
+
+ nextFrame = nextG[player]? kNoSuction:
+ (nextM[player]? kFlashDarkBlob: jiggle[nextStage[player][1]]);
+
+ SurfaceDrawShadow( &shadowRect, nextA[player], nextFrame );
+
+ CalcBlobRect( nextFrame, nextA[player]-1, &srcRect );
+ SurfaceBlitBlob( &srcRect, &blobRect );
+
+ SDLU_ReleaseSurface( nextDrawSurface );
+
+ SDLU_BlitFrontSurface( nextDrawSurface,
+ SDLU_MRectToSDLRect( &nextWindowZRect, &sourceSDLRect ),
+ SDLU_MRectToSDLRect( &nextWindowRect[player], &destSDLRect ) );
+ }
+}
--- a/src/next.cpp
+++ /dev/null
@@ -1,208 +1,0 @@
-// next.c
-
-#include "SDLU.h"
-
-#include "main.h"
-#include "next.h"
-#include "graphics.h"
-#include "gworld.h"
-#include "gameticks.h"
-#include "random.h"
-#include "blitter.h"
-#include "level.h"
-
-#define kJiggleFrames 8
-#define kPulling 10
-#define kPullingFrames 18
-
-SDL_Surface* nextSurface;
-SDL_Surface* nextDrawSurface;
-
-MRect nextWindowZRect, nextWindowRect[2];
-MBoolean nextWindowVisible[2] = {true, true};
-MTicks nextTime[2][2];
-int nextStage[2][2], pullA[2], pullB[2];
-
-void InitNext( void )
-{
- const double windowLoc[] = {0.46, 0.54};
- SDL_Rect sdlRect;
-
- nextWindowZRect.top = nextWindowZRect.left = 0;
- nextWindowZRect.bottom = 72; nextWindowZRect.right = 32;
-
- nextWindowRect[0] = nextWindowRect[1] = nextWindowZRect;
- CenterRectOnScreen( &nextWindowRect[0], windowLoc[0], 0.25 );
- CenterRectOnScreen( &nextWindowRect[1], windowLoc[1], 0.25 );
-
- nextSurface = LoadPICTAsSurface( picNext, 32 );
-
- nextDrawSurface = SDLU_InitSurface( SDLU_MRectToSDLRect( &nextWindowZRect, &sdlRect ), 32 );
-}
-
-void RefreshNext( int player )
-{
- nextStage[player][0] = 0;
- nextStage[player][1] = 0;
-
- nextTime[player][0] = GameTickCount( ) + RandomBefore( 60 );
- nextTime[player][1] = GameTickCount( ) + RandomBefore( 60 );
-
- ShowNext( player );
-}
-
-void PullNext( int player )
-{
- pullA[player] = nextA[player];
- pullB[player] = nextB[player];
- nextStage[player][0] = kPulling;
- nextTime[player][0] = GameTickCount( );
-}
-
-#define kNoDraw 999
-void ShowPull( int player )
-{
- MRect srcRect;
- int yank[8] = { 20, 18, 15, 8, -6, -26, -46, -66 };
- int slide[8] = { kNoDraw, 66, 48, 36, 29, 26, 24, 23 };
- int drawA, drawB, offset, count;
- SDL_Rect sourceSDLRect, destSDLRect;
-
- if( !nextWindowVisible[player] ) return;
-
- SDLU_AcquireSurface( nextDrawSurface );
-
- SDLU_BlitSurface( nextSurface, &nextSurface->clip_rect,
- nextDrawSurface, &nextDrawSurface->clip_rect );
-
- for( count=0; count<2; count++ )
- {
- offset = nextStage[player][0] - kPulling;
-
- switch( count )
- {
- case 0: drawA = pullA[player]; drawB = pullB[player]; offset = yank[offset]; break;
- case 1: drawA = nextA[player]; drawB = nextB[player]; offset = slide[offset]; break;
- }
-
- if( offset != kNoDraw )
- {
- MRect blobRect = { 0, 4, 0 + kBlobVertSize, 4 + kBlobHorizSize };
- MRect shadowRect = { 4, 8, 4 + kBlobVertSize, 8 + kBlobHorizSize };
-
- OffsetMRect( &blobRect, 0, offset );
- OffsetMRect( &shadowRect, 0, offset );
-
- SurfaceDrawShadow( &shadowRect, drawB, kNoSuction );
-
- CalcBlobRect( kNoSuction, drawB-1, &srcRect );
- SurfaceBlitBlob( &srcRect, &blobRect );
-
- OffsetMRect( &blobRect, 0, kBlobVertSize );
- OffsetMRect( &shadowRect, 0, kBlobVertSize );
-
- SurfaceDrawShadow( &shadowRect, drawA, nextM[player]? kFlashDarkBlob: kNoSuction );
-
- CalcBlobRect( nextM[player]? kFlashDarkBlob: kNoSuction, drawA-1, &srcRect );
- SurfaceBlitBlob( &srcRect, &blobRect );
- }
- }
-
- SDLU_ReleaseSurface( nextDrawSurface );
-
- SDLU_BlitFrontSurface( nextDrawSurface,
- SDLU_MRectToSDLRect( &nextWindowZRect, &sourceSDLRect ),
- SDLU_MRectToSDLRect( &nextWindowRect[player], &destSDLRect ) );
-}
-
-void UpdateNext( int player )
-{
- MBoolean changed = false;
- int blob;
-
- if( nextStage[player][0] >= kPulling )
- {
- if( GameTickCount() > nextTime[player][0] )
- {
- if( ++nextStage[player][0] >= kPullingFrames )
- {
- RefreshNext( player );
- }
- else
- {
- ShowPull( player );
- nextTime[player][0]++;
- }
- }
- }
- else
- {
- for( blob=0; blob<2; blob++ )
- {
- if( GameTickCount() > nextTime[player][blob] )
- {
- if( ++nextStage[player][blob] >= kJiggleFrames )
- {
- nextStage[player][blob] = 0;
- nextTime[player][blob] += 40 + RandomBefore( 80 );
- }
- else
- {
- nextTime[player][blob] += 2;
- }
-
- changed = true;
- }
- }
-
- if( changed ) ShowNext( player );
- }
-}
-
-void ShowNext( int player )
-{
- int jiggle[kJiggleFrames] = { kNoSuction, kSquish, kNoSuction, kSquash,
- kNoSuction, kSquish, kNoSuction, kSquash };
- int nextFrame = kNoSuction;
- MRect blobRect = { 22, 4, 22 + kBlobVertSize, 4 + kBlobHorizSize };
- MRect shadowRect = { 26, 8, 26 + kBlobVertSize, 8 + kBlobHorizSize };
- MRect srcRect;
- SDL_Rect sourceSDLRect, destSDLRect;
-
- if( !nextWindowVisible[player] ) return;
-
- if( control[player] == kNobodyControl )
- {
- }
- else
- {
- SDLU_AcquireSurface( nextDrawSurface );
-
- SDLU_BlitSurface( nextSurface, &nextSurface->clip_rect,
- nextDrawSurface, &nextDrawSurface->clip_rect );
-
- nextFrame = nextG[player]? kNoSuction: jiggle[nextStage[player][0]];
-
- SurfaceDrawShadow( &shadowRect, nextB[player], nextFrame );
-
- CalcBlobRect( nextFrame, nextB[player]-1, &srcRect );
- SurfaceBlitBlob( &srcRect, &blobRect );
-
- OffsetMRect( &blobRect, 0, kBlobVertSize );
- OffsetMRect( &shadowRect, 0, kBlobVertSize );
-
- nextFrame = nextG[player]? kNoSuction:
- (nextM[player]? kFlashDarkBlob: jiggle[nextStage[player][1]]);
-
- SurfaceDrawShadow( &shadowRect, nextA[player], nextFrame );
-
- CalcBlobRect( nextFrame, nextA[player]-1, &srcRect );
- SurfaceBlitBlob( &srcRect, &blobRect );
-
- SDLU_ReleaseSurface( nextDrawSurface );
-
- SDLU_BlitFrontSurface( nextDrawSurface,
- SDLU_MRectToSDLRect( &nextWindowZRect, &sourceSDLRect ),
- SDLU_MRectToSDLRect( &nextWindowRect[player], &destSDLRect ) );
- }
-}
--- /dev/null
+++ b/src/opponent.c
@@ -1,0 +1,257 @@
+// opponent.c
+
+#include "SDLU.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "main.h"
+#include "level.h"
+#include "opponent.h"
+#include "gworld.h"
+#include "graphics.h"
+#include "random.h"
+#include "control.h"
+#include "players.h"
+#include "gameticks.h"
+#include "blitter.h"
+
+SDL_Surface* opponentSurface;
+SDL_Surface* opponentMaskSurface;
+SDL_Surface* opponentDrawSurface;
+
+MRect opponentWindowZRect, opponentWindowRect;
+int opponentMood, opponentFrame;
+MTicks opponentTime, glowTime[kGlows], panicTime;
+int glowFrame[kGlows], panicFrame;
+int heavyGlowArray[kGlowArraySize], glowArray[kGlowArraySize], lightGlowArray[kGlowArraySize];
+
+void InitOpponent( void )
+{
+ MRect littleRect = {0, 0, 64, 64}, bigRect = {0, 0, 64, 64*(kOppFrames*3) };
+ SDL_Rect sdlRect;
+ double index, value;
+
+ opponentDrawSurface = SDLU_InitSurface( SDLU_MRectToSDLRect( &littleRect, &sdlRect ), 32 );
+ opponentSurface = SDLU_InitSurface( SDLU_MRectToSDLRect( &bigRect, &sdlRect ), 32 );
+
+ bigRect.bottom *= kGlows + 1;
+ opponentMaskSurface = SDLU_InitSurface( SDLU_MRectToSDLRect( &bigRect, &sdlRect ), MASK_DEPTH );
+
+ opponentWindowZRect.top = opponentWindowZRect.left = 0;
+ opponentWindowZRect.bottom = opponentWindowZRect.right = 64;
+ opponentWindowRect = opponentWindowZRect;
+ CenterRectOnScreen( &opponentWindowRect, 0.5, 0.5 );
+
+ opponentMood = 0;
+
+ for( index=0; index<kGlowArraySize; index++ )
+ {
+ value = sin( index*kPi/kGlowArraySize );
+ value *= value;
+
+ heavyGlowArray[(int)index] = (int)(value * 0.75 * 256);
+ glowArray [(int)index] = (int)(value * 0.50 * 256);
+ lightGlowArray[(int)index] = (int)(value * 0.375 * 256);
+ }
+}
+
+void BeginOpponent( int which )
+{
+ int count;
+
+ DrawPICTInSurface( opponentSurface, 5000 + which );
+ DrawPICTInSurface( opponentMaskSurface, 5100 + which );
+
+ opponentTime = panicTime = GameTickCount( );
+ for( count=0; count<kGlows; count++ )
+ {
+ glowTime[count] = panicTime;
+ glowFrame[count] = 0;
+ }
+
+ opponentMood = 0;
+ emotions[0] = emotions[1] = kEmotionNeutral;
+}
+
+void DrawFrozenOpponent( void )
+{
+ SDL_Rect sourceSDLRect, destSDLRect;
+ MRect myRect = {0, 0, 64, 64};
+
+ OffsetMRect( &myRect, opponentFrame * 64, 0 );
+
+ SDLU_BlitFrontSurface( opponentSurface,
+ SDLU_MRectToSDLRect( &myRect, &sourceSDLRect ),
+ SDLU_MRectToSDLRect( &opponentWindowRect, &destSDLRect ) );
+}
+
+void OpponentPissed( void )
+{
+ opponentMood = 7;
+ opponentTime = GameTickCount();
+}
+
+void OpponentChatter( MBoolean on )
+{
+ switch( on )
+ {
+ case true:
+ opponentMood = 5;
+ opponentTime = GameTickCount();
+ break;
+
+ case false:
+ opponentMood = 0;
+ opponentTime = GameTickCount();
+ break;
+ }
+}
+
+void UpdateOpponent( void )
+{
+ MRect myRect = {0,0,64,64}, dstRect = {0,0,64,64}, maskRect;
+ int emotiMap[] = {0, 1, 2, 1}, draw = false, count;
+ SDL_Rect srcSDLRect, dstSDLRect;
+
+ if( GameTickCount( ) > opponentTime )
+ {
+ switch( opponentMood )
+ {
+ case 0: // Idle
+ opponentTime += 60 + RandomBefore(180);
+ opponentMood = RandomBefore(2) + 1;
+ opponentFrame = (emotiMap[emotions[1]] * kOppFrames);
+ break;
+
+ case 1: // Shifty Eyes
+ opponentTime += 40 + RandomBefore(60);
+ opponentMood = 0;
+ opponentFrame = (emotiMap[emotions[1]] * kOppFrames) + RandomBefore(2) + 1;
+ break;
+
+ case 2: // Blinks
+ opponentTime += 3;
+ opponentMood = 3;
+ opponentFrame = (emotiMap[emotions[1]] * kOppFrames) + 3;
+ break;
+
+ case 3: // Blinks (more)
+ opponentTime += 3;
+ opponentMood = 4;
+ opponentFrame = (emotiMap[emotions[1]] * kOppFrames) + 4;
+ break;
+
+ case 4: // Blinks (more)
+ opponentTime += 3;
+ opponentMood = 0;
+ opponentFrame = (emotiMap[emotions[1]] * kOppFrames) + 3;
+ break;
+
+ case 5: // Chatter (only good for tutorial)
+ opponentTime += 8;
+ opponentMood = 6;
+ opponentFrame = 5;
+ break;
+
+ case 6: // Chatter 2 (only good for tutorial)
+ opponentTime += 8;
+ opponentMood = 5;
+ opponentFrame = 6;
+ break;
+
+ case 7: // Pissed (when hit with punishments)
+ opponentTime += 60;
+ opponentFrame = 7;
+ opponentMood = 0;
+ break;
+ }
+
+ draw = true;
+ }
+
+ if( GameTickCount( ) > panicTime )
+ {
+ panicTime += 2;
+
+ if( emotions[1] == kEmotionPanic )
+ {
+ if( ++panicFrame >= kGlowArraySize ) panicFrame = 0;
+ draw = true;
+ }
+ else
+ {
+ panicFrame = 0;
+ }
+ }
+
+ for( count=0; count<kGlows; count++ )
+ {
+ if( GameTickCount( ) > glowTime[count] )
+ {
+ glowTime[count] += character[1].glow[count].time;
+
+ if( character[1].glow[count].colorR || character[1].glow[count].colorG || character[1].glow[count].colorB )
+ {
+ if( ++glowFrame[count] >= kGlowArraySize ) glowFrame[count] = 0;
+ draw = true;
+ }
+ else
+ {
+ glowFrame[count] = 0;
+ }
+ }
+ }
+
+ if( draw )
+ {
+ OffsetMRect( &myRect, 64*opponentFrame, 0 );
+
+ SDLU_AcquireSurface( opponentDrawSurface );
+
+ SDLU_BlitSurface( opponentSurface, SDLU_MRectToSDLRect( &myRect, &srcSDLRect ),
+ opponentDrawSurface, SDLU_MRectToSDLRect( &dstRect, &dstSDLRect ) );
+
+ maskRect = myRect;
+ for( count=0; count<kGlows; count++ )
+ {
+ OffsetMRect( &maskRect, 0, 64 );
+
+ if( glowFrame[count] )
+ {
+ if( character[1].glow[count].isHeavy )
+ {
+ SurfaceBlitColor( opponentMaskSurface, opponentDrawSurface,
+ &maskRect, &dstRect,
+ character[1].glow[count].colorR,
+ character[1].glow[count].colorG,
+ character[1].glow[count].colorB,
+ heavyGlowArray[glowFrame[count]] );
+ }
+ else
+ {
+ SurfaceBlitColor( opponentMaskSurface, opponentDrawSurface,
+ &maskRect, &dstRect,
+ character[1].glow[count].colorR,
+ character[1].glow[count].colorG,
+ character[1].glow[count].colorB,
+ lightGlowArray[glowFrame[count]] );
+ }
+ }
+ }
+
+ if( panicFrame )
+ {
+ SurfaceBlitColor( opponentMaskSurface, opponentDrawSurface,
+ &myRect, &dstRect,
+ _5TO8(31), _5TO8(31), _5TO8(22), glowArray[panicFrame] );
+ }
+
+ SDLU_ReleaseSurface( opponentDrawSurface );
+
+ SDLU_BlitFrontSurface( opponentDrawSurface,
+ SDLU_MRectToSDLRect( &opponentWindowZRect, &srcSDLRect ),
+ SDLU_MRectToSDLRect( &opponentWindowRect, &dstSDLRect ) );
+ }
+}
--- a/src/opponent.cpp
+++ /dev/null
@@ -1,257 +1,0 @@
-// opponent.c
-
-#include "SDLU.h"
-
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "main.h"
-#include "level.h"
-#include "opponent.h"
-#include "gworld.h"
-#include "graphics.h"
-#include "random.h"
-#include "control.h"
-#include "players.h"
-#include "gameticks.h"
-#include "blitter.h"
-
-SDL_Surface* opponentSurface;
-SDL_Surface* opponentMaskSurface;
-SDL_Surface* opponentDrawSurface;
-
-MRect opponentWindowZRect, opponentWindowRect;
-int opponentMood, opponentFrame;
-MTicks opponentTime, glowTime[kGlows], panicTime;
-int glowFrame[kGlows], panicFrame;
-int heavyGlowArray[kGlowArraySize], glowArray[kGlowArraySize], lightGlowArray[kGlowArraySize];
-
-void InitOpponent( void )
-{
- MRect littleRect = {0, 0, 64, 64}, bigRect = {0, 0, 64, 64*(kOppFrames*3) };
- SDL_Rect sdlRect;
- double index, value;
-
- opponentDrawSurface = SDLU_InitSurface( SDLU_MRectToSDLRect( &littleRect, &sdlRect ), 32 );
- opponentSurface = SDLU_InitSurface( SDLU_MRectToSDLRect( &bigRect, &sdlRect ), 32 );
-
- bigRect.bottom *= kGlows + 1;
- opponentMaskSurface = SDLU_InitSurface( SDLU_MRectToSDLRect( &bigRect, &sdlRect ), MASK_DEPTH );
-
- opponentWindowZRect.top = opponentWindowZRect.left = 0;
- opponentWindowZRect.bottom = opponentWindowZRect.right = 64;
- opponentWindowRect = opponentWindowZRect;
- CenterRectOnScreen( &opponentWindowRect, 0.5, 0.5 );
-
- opponentMood = 0;
-
- for( index=0; index<kGlowArraySize; index++ )
- {
- value = sin( index*pi/kGlowArraySize );
- value *= value;
-
- heavyGlowArray[(int)index] = (int)(value * 0.75 * 256);
- glowArray [(int)index] = (int)(value * 0.50 * 256);
- lightGlowArray[(int)index] = (int)(value * 0.375 * 256);
- }
-}
-
-void BeginOpponent( int which )
-{
- int count;
-
- DrawPICTInSurface( opponentSurface, 5000 + which );
- DrawPICTInSurface( opponentMaskSurface, 5100 + which );
-
- opponentTime = panicTime = GameTickCount( );
- for( count=0; count<kGlows; count++ )
- {
- glowTime[count] = panicTime;
- glowFrame[count] = 0;
- }
-
- opponentMood = 0;
- emotions[0] = emotions[1] = kEmotionNeutral;
-}
-
-void DrawFrozenOpponent( void )
-{
- SDL_Rect sourceSDLRect, destSDLRect;
- MRect myRect = {0, 0, 64, 64};
-
- OffsetMRect( &myRect, opponentFrame * 64, 0 );
-
- SDLU_BlitFrontSurface( opponentSurface,
- SDLU_MRectToSDLRect( &myRect, &sourceSDLRect ),
- SDLU_MRectToSDLRect( &opponentWindowRect, &destSDLRect ) );
-}
-
-void OpponentPissed( void )
-{
- opponentMood = 7;
- opponentTime = GameTickCount();
-}
-
-void OpponentChatter( MBoolean on )
-{
- switch( on )
- {
- case true:
- opponentMood = 5;
- opponentTime = GameTickCount();
- break;
-
- case false:
- opponentMood = 0;
- opponentTime = GameTickCount();
- break;
- }
-}
-
-void UpdateOpponent( void )
-{
- MRect myRect = {0,0,64,64}, dstRect = {0,0,64,64}, maskRect;
- int emotiMap[] = {0, 1, 2, 1}, draw = false, count;
- SDL_Rect srcSDLRect, dstSDLRect;
-
- if( GameTickCount( ) > opponentTime )
- {
- switch( opponentMood )
- {
- case 0: // Idle
- opponentTime += 60 + RandomBefore(180);
- opponentMood = RandomBefore(2) + 1;
- opponentFrame = (emotiMap[emotions[1]] * kOppFrames);
- break;
-
- case 1: // Shifty Eyes
- opponentTime += 40 + RandomBefore(60);
- opponentMood = 0;
- opponentFrame = (emotiMap[emotions[1]] * kOppFrames) + RandomBefore(2) + 1;
- break;
-
- case 2: // Blinks
- opponentTime += 3;
- opponentMood = 3;
- opponentFrame = (emotiMap[emotions[1]] * kOppFrames) + 3;
- break;
-
- case 3: // Blinks (more)
- opponentTime += 3;
- opponentMood = 4;
- opponentFrame = (emotiMap[emotions[1]] * kOppFrames) + 4;
- break;
-
- case 4: // Blinks (more)
- opponentTime += 3;
- opponentMood = 0;
- opponentFrame = (emotiMap[emotions[1]] * kOppFrames) + 3;
- break;
-
- case 5: // Chatter (only good for tutorial)
- opponentTime += 8;
- opponentMood = 6;
- opponentFrame = 5;
- break;
-
- case 6: // Chatter 2 (only good for tutorial)
- opponentTime += 8;
- opponentMood = 5;
- opponentFrame = 6;
- break;
-
- case 7: // Pissed (when hit with punishments)
- opponentTime += 60;
- opponentFrame = 7;
- opponentMood = 0;
- break;
- }
-
- draw = true;
- }
-
- if( GameTickCount( ) > panicTime )
- {
- panicTime += 2;
-
- if( emotions[1] == kEmotionPanic )
- {
- if( ++panicFrame >= kGlowArraySize ) panicFrame = 0;
- draw = true;
- }
- else
- {
- panicFrame = 0;
- }
- }
-
- for( count=0; count<kGlows; count++ )
- {
- if( GameTickCount( ) > glowTime[count] )
- {
- glowTime[count] += character[1].glow[count].time;
-
- if( character[1].glow[count].colorR || character[1].glow[count].colorG || character[1].glow[count].colorB )
- {
- if( ++glowFrame[count] >= kGlowArraySize ) glowFrame[count] = 0;
- draw = true;
- }
- else
- {
- glowFrame[count] = 0;
- }
- }
- }
-
- if( draw )
- {
- OffsetMRect( &myRect, 64*opponentFrame, 0 );
-
- SDLU_AcquireSurface( opponentDrawSurface );
-
- SDLU_BlitSurface( opponentSurface, SDLU_MRectToSDLRect( &myRect, &srcSDLRect ),
- opponentDrawSurface, SDLU_MRectToSDLRect( &dstRect, &dstSDLRect ) );
-
- maskRect = myRect;
- for( count=0; count<kGlows; count++ )
- {
- OffsetMRect( &maskRect, 0, 64 );
-
- if( glowFrame[count] )
- {
- if( character[1].glow[count].isHeavy )
- {
- SurfaceBlitColor( opponentMaskSurface, opponentDrawSurface,
- &maskRect, &dstRect,
- character[1].glow[count].colorR,
- character[1].glow[count].colorG,
- character[1].glow[count].colorB,
- heavyGlowArray[glowFrame[count]] );
- }
- else
- {
- SurfaceBlitColor( opponentMaskSurface, opponentDrawSurface,
- &maskRect, &dstRect,
- character[1].glow[count].colorR,
- character[1].glow[count].colorG,
- character[1].glow[count].colorB,
- lightGlowArray[glowFrame[count]] );
- }
- }
- }
-
- if( panicFrame )
- {
- SurfaceBlitColor( opponentMaskSurface, opponentDrawSurface,
- &myRect, &dstRect,
- _5TO8(31), _5TO8(31), _5TO8(22), glowArray[panicFrame] );
- }
-
- SDLU_ReleaseSurface( opponentDrawSurface );
-
- SDLU_BlitFrontSurface( opponentDrawSurface,
- SDLU_MRectToSDLRect( &opponentWindowZRect, &srcSDLRect ),
- SDLU_MRectToSDLRect( &opponentWindowRect, &dstSDLRect ) );
- }
-}
--- /dev/null
+++ b/src/pause.c
@@ -1,0 +1,1334 @@
+// pause.cpp
+
+// All of this code is fugly. I really needed a dialog manager, but I didn't know it at the time,
+// and instead I cobbled this together. It is just barely good enough to work. Fortunately it looks
+// decent to the end user...
+
+
+#include "SDLU.h"
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "main.h"
+#include "gameticks.h"
+#include "blitter.h"
+#include "graphics.h"
+#include "gworld.h"
+#include "pause.h"
+#include "random.h"
+#include "font.h"
+#include "music.h"
+#include "soundfx.h"
+#include "keyselect.h"
+#include "level.h"
+#include "victory.h"
+#include "hiscore.h"
+#include "score.h"
+
+typedef struct FRGBColor
+{
+ float red, green, blue;
+} FRGBColor;
+
+typedef struct ClickableZone
+{
+ int item;
+ MRect rect;
+} ClickableZone;
+
+SDL_Surface* backSurface;
+SDL_Surface* drawSurface;
+SDL_Surface* logoSurface;
+SDL_Surface* logoMaskSurface;
+SDL_Surface* logoAlphaSurface;
+
+SkittlesFontPtr smallFont, bigFont, dashedLineFont, continueFont, tinyFont, batsuFont;
+FRGBColor backColor[4];
+MBoolean continueTimeOut;
+
+static int dialogType, dialogStage, dialogTarget, dialogShade, dialogItem;
+MTicks dialogTimer;
+static float colorWrap = 0, colorInc;
+static MRect logoRect = {0, 0, 111, 246}, lastPauseRect;
+static MBoolean dialogStageComplete;
+static MBoolean timeToRedraw = false;
+
+// for the controls dialog
+static int controlToReplace = -1;
+
+// for the enter code dialog
+static char nameField[256], keyField[256];
+static char* whichField = nameField;
+static int batsuAlpha = 0;
+
+static void ItsTimeToRedraw()
+{
+ timeToRedraw = true;
+}
+
+enum
+{
+ kTextRainbow,
+ kTextBrightRainbow,
+ kTextWhite,
+ kTextBlueGlow,
+ kTextGray,
+ kTextAlmostWhite
+};
+
+static MPoint DrawRainbowText( SkittlesFontPtr font, const char *line, MPoint dPoint, float wave, int bright )
+{
+ int current;
+ int r,g,b;
+ float s;
+
+ current = 0;
+
+ switch( bright )
+ {
+ case kTextGray:
+ r = g = b = 96;
+ break;
+
+ case kTextBlueGlow:
+ s = sin(wave);
+ r = (int)(88.0 + 120.0 * s * s);
+ g = r;
+ b = 255;
+ break;
+
+ case kTextWhite:
+ r = g = b = 255;
+ break;
+
+ case kTextAlmostWhite:
+ default:
+ r = g = b = 224;
+ break;
+
+ }
+
+ while( line[current] )
+ {
+ switch( bright )
+ {
+ case kTextBrightRainbow:
+ r = (int)(208.0 + 40.0 * sin(wave ));
+ g = (int)(208.0 + 40.0 * sin(wave + ((2.*kPi) * 1./3.)));
+ b = (int)(208.0 + 40.0 * sin(wave + ((2.*kPi) * 2./3.)));
+ break;
+
+ case kTextRainbow:
+ r = (int)(128.0 + 96.0 * sin(wave ));
+ g = (int)(128.0 + 96.0 * sin(wave + ((2.*kPi) * 1./3.)));
+ b = (int)(128.0 + 96.0 * sin(wave + ((2.*kPi) * 2./3.)));
+ break;
+ }
+
+ SurfaceBlitCharacter( font, line[current], &dPoint, r, g, b, 1 );
+
+ wave += 0.2;
+ current++;
+ }
+
+ return dPoint;
+}
+
+
+#define kEdgeSize 8
+static COLOR_T edge[4][kEdgeSize][kEdgeSize];
+
+void SurfaceGetEdges( SDL_Surface* edgeSurface, const MRect *rect )
+{
+ unsigned char* src[4];
+ int srcRowBytes;
+
+ src[0] = src[1] = src[2] = src[3] = (unsigned char*) edgeSurface->pixels;
+ srcRowBytes = edgeSurface->pitch;
+
+ src[0] += (srcRowBytes * (rect->top )) + ((rect->left ) * BYTES_PER_PIXEL);
+ src[1] += (srcRowBytes * (rect->top )) + ((rect->right - kEdgeSize) * BYTES_PER_PIXEL);
+ src[2] += (srcRowBytes * (rect->bottom - kEdgeSize)) + ((rect->left ) * BYTES_PER_PIXEL);
+ src[3] += (srcRowBytes * (rect->bottom - kEdgeSize)) + ((rect->right - kEdgeSize) * BYTES_PER_PIXEL);
+
+ for (int count=0; count<4; count++)
+ {
+ for (int height=0; height<kEdgeSize; height++)
+ {
+ memcpy( edge[count][height], src[count], kEdgeSize * BYTES_PER_PIXEL );
+ src[count] += srcRowBytes;
+ }
+ }
+}
+
+
+void SurfaceCurveEdges( SDL_Surface* edgeSurface, const MRect *rect )
+{
+ unsigned char* src[4];
+ int srcRowBytes, width, height, count;
+ char edgeMap[4][kEdgeSize][kEdgeSize+1]={ " --",
+ " -...",
+ " -.xxX",
+ " -.xXXX",
+ " -.xXXXX",
+ " .xXXXXX",
+ "-.xXXXXX",
+ "-.XXXXXX",
+ "-- ",
+ "...- ",
+ "Xxx.- ",
+ "XXXx.- ",
+ "XXXXx.- ",
+ "XXXXXx. ",
+ "XXXXXx.-",
+ "XXXXXX.-",
+ "-.XXXXXX",
+ "-.xXXXXX",
+ " .xXXXXX",
+ " -.xXXXX",
+ " -.xXXX",
+ " -.xxX",
+ " -...",
+ " --",
+ "XXXXXX.-",
+ "XXXXXx.-",
+ "XXXXXx. ",
+ "XXXXx.- ",
+ "XXXx.- ",
+ "Xxx.- ",
+ "...- ",
+ "-- " };
+
+
+ src[0] = src[1] = src[2] = src[3] = (unsigned char*) edgeSurface->pixels;
+ srcRowBytes = edgeSurface->pitch;
+
+ src[0] += (srcRowBytes * (rect->top )) + ((rect->left ) * BYTES_PER_PIXEL);
+ src[1] += (srcRowBytes * (rect->top )) + ((rect->right - kEdgeSize) * BYTES_PER_PIXEL);
+ src[2] += (srcRowBytes * (rect->bottom - kEdgeSize)) + ((rect->left ) * BYTES_PER_PIXEL);
+ src[3] += (srcRowBytes * (rect->bottom - kEdgeSize)) + ((rect->right - kEdgeSize) * BYTES_PER_PIXEL);
+
+ const int HALFBRIGHT_MASK =
+ (CHANNEL_MASK >> 1)
+ | ((CHANNEL_MASK >> 1) << BITS_PER_1CHANNEL)
+ | ((CHANNEL_MASK >> 1) << BITS_PER_2CHANNELS);
+
+ // Draw top/bottom border
+ {
+ COLOR_T *srcT1 = (COLOR_T*) (src[0]) + kEdgeSize;
+ COLOR_T *srcB1 = (COLOR_T*) (src[2] + (srcRowBytes*(kEdgeSize-1))) + kEdgeSize;
+ COLOR_T *srcT2 = srcT1 + (srcRowBytes / BYTES_PER_PIXEL);
+ COLOR_T *srcB2 = srcB1 - (srcRowBytes / BYTES_PER_PIXEL);
+
+ for( width = rect->right - rect->left - (kEdgeSize * 2); width > 0; width-- )
+ {
+ *srcT1 = 0; srcT1++;
+ *srcB1 = 0; srcB1++;
+ *srcT2 = (*srcT2 >> 1) & HALFBRIGHT_MASK; srcT2++;
+ *srcB2 = (*srcB2 >> 1) & HALFBRIGHT_MASK; srcB2++;
+ }
+ }
+
+ // Draw left/right border
+ {
+ unsigned char *srcL1 = (src[0] + (srcRowBytes * kEdgeSize));
+ unsigned char *srcR1 = (src[1] + (srcRowBytes * kEdgeSize)) + BYTES_PER_PIXEL * (kEdgeSize-1);
+
+ unsigned char *srcL2 = srcL1 + BYTES_PER_PIXEL;
+ unsigned char *srcR2 = srcR1 - BYTES_PER_PIXEL;
+
+ for( height = rect->bottom - rect->top - (kEdgeSize * 2); height > 0; height-- )
+ {
+ *(COLOR_T*)srcL1 = 0;
+ *(COLOR_T*)srcR1 = 0;
+ *(COLOR_T*)srcL2 = (*(COLOR_T*)srcL2 >> 1) & HALFBRIGHT_MASK;
+ *(COLOR_T*)srcR2 = (*(COLOR_T*)srcR2 >> 1) & HALFBRIGHT_MASK;
+
+ srcL1 += srcRowBytes;
+ srcR1 += srcRowBytes;
+ srcL2 += srcRowBytes;
+ srcR2 += srcRowBytes;
+ }
+ }
+
+ // Draw curved edges
+ for( count=0; count<4; count++ )
+ {
+ COLOR_T *srcS = (COLOR_T*) src[count];
+
+ for( height=0; height<kEdgeSize; height++ )
+ {
+ for( width=0; width<kEdgeSize; width++ )
+ {
+ switch( edgeMap[count][height][width] )
+ {
+ case ' ': *srcS = edge[count][height][width]; break;
+ case '-': *srcS = (edge[count][height][width] >> 1) & HALFBRIGHT_MASK; break;
+ case '.': *srcS = 0; break;
+ case 'x': *srcS = (*srcS >> 1) & HALFBRIGHT_MASK; break;
+ case 'X': break;
+ }
+ srcS++;
+ }
+ srcS += (srcRowBytes / BYTES_PER_PIXEL) - kEdgeSize;
+ }
+ }
+}
+
+enum
+{
+ kOpening = 0,
+ kClosing
+};
+
+static MBoolean DrawDialogBox( MBoolean larger, int animationType, int *target, int skip, float *colorWrap, float colorInc, MRect *pauseRect )
+{
+ MBoolean animationStageComplete = false;
+ MRect normalRect[2][19] = { { { 240 - 10, 320 - 30, 240 + 10, 320 + 30 },
+ { 240 - 40, 320 - 120, 240 + 40, 320 + 120 },
+ { 240 - 60, 320 - 180, 240 + 60, 320 + 180 },
+ { 240 - 70, 320 - 210, 240 + 70, 320 + 210 },
+ { 240 - 80, 320 - 230, 240 + 80, 320 + 230 },
+ { 240 - 88, 320 - 245, 240 + 88, 320 + 245 },
+ { 240 - 95, 320 - 252, 240 + 95, 320 + 252 },
+ { 240 - 101, 320 - 255, 240 + 101, 320 + 255 },
+ { 240 - 106, 320 - 252, 240 + 106, 320 + 252 },
+ { 240 - 110, 320 - 245, 240 + 110, 320 + 245 },
+ { 240 - 113, 320 - 238, 240 + 113, 320 + 238 },
+ { 240 - 115, 320 - 232, 240 + 115, 320 + 232 },
+ { 240 - 116, 320 - 228, 240 + 116, 320 + 228 },
+ { 240 - 118, 320 - 232, 240 + 118, 320 + 230 },
+ { 240 - 118, 320 - 238, 240 + 118, 320 + 232 },
+ { 240 - 119, 320 - 242, 240 + 119, 320 + 242 },
+ { 240 - 119, 320 - 244, 240 + 119, 320 + 244 },
+ { 240 - 119, 320 - 242, 240 + 119, 320 + 242 },
+ { 240 - 120, 320 - 240, 240 + 120, 320 + 240 } },
+ { { 240 - 110, 320 - 220, 240 + 110, 320 + 220 },
+ { 240 - 105, 320 - 210, 240 + 105, 320 + 210 },
+ { 240 - 100, 320 - 200, 240 + 100, 320 + 200 },
+ { 240 - 95, 320 - 190, 240 + 95, 320 + 190 },
+ { 240 - 90, 320 - 180, 240 + 90, 320 + 180 },
+ { 240 - 85, 320 - 170, 240 + 85, 320 + 170 },
+ { 240 - 80, 320 - 160, 240 + 80, 320 + 160 },
+ { 240 - 75, 320 - 150, 240 + 75, 320 + 150 },
+ { 240 - 70, 320 - 140, 240 + 70, 320 + 140 },
+ { 240 - 65, 320 - 130, 240 + 65, 320 + 130 },
+ { 240 - 60, 320 - 120, 240 + 60, 320 + 120 },
+ { 240 - 55, 320 - 110, 240 + 55, 320 + 110 },
+ { 240 - 50, 320 - 100, 240 + 50, 320 + 100 },
+ { 240 - 45, 320 - 90, 240 + 45, 320 + 90 },
+ { 240 - 40, 320 - 80, 240 + 40, 320 + 80 },
+ { 240 - 35, 320 - 70, 240 + 35, 320 + 70 },
+ { 240 - 30, 320 - 60, 240 + 30, 320 + 60 },
+ { 240 - 25, 320 - 50, 240 + 25, 320 + 50 },
+ { 240 - 20, 320 - 40, 240 + 20, 320 + 40 } }
+ };
+
+ MRect largerRect[2][19] = { { { 240 - 11, 320 - 30, 240 + 11, 320 + 30 },
+ { 240 - 44, 320 - 120, 240 + 44, 320 + 120 },
+ { 240 - 66, 320 - 180, 240 + 66, 320 + 180 },
+ { 240 - 77, 320 - 210, 240 + 77, 320 + 210 },
+ { 240 - 88, 320 - 230, 240 + 88, 320 + 230 },
+ { 240 - 97, 320 - 245, 240 + 97, 320 + 245 },
+ { 240 - 104, 320 - 252, 240 + 104, 320 + 252 },
+ { 240 - 111, 320 - 255, 240 + 111, 320 + 255 },
+ { 240 - 117, 320 - 252, 240 + 117, 320 + 252 },
+ { 240 - 121, 320 - 245, 240 + 121, 320 + 245 },
+ { 240 - 124, 320 - 238, 240 + 124, 320 + 238 },
+ { 240 - 126, 320 - 232, 240 + 126, 320 + 232 },
+ { 240 - 128, 320 - 228, 240 + 128, 320 + 228 },
+ { 240 - 130, 320 - 232, 240 + 130, 320 + 230 },
+ { 240 - 130, 320 - 238, 240 + 130, 320 + 232 },
+ { 240 - 131, 320 - 242, 240 + 131, 320 + 242 },
+ { 240 - 131, 320 - 244, 240 + 131, 320 + 244 },
+ { 240 - 131, 320 - 242, 240 + 131, 320 + 242 },
+ { 240 - 132, 320 - 240, 240 + 132, 320 + 240 } },
+ { { 240 - 121, 320 - 220, 240 + 121, 320 + 220 },
+ { 240 - 115, 320 - 210, 240 + 115, 320 + 210 },
+ { 240 - 110, 320 - 200, 240 + 110, 320 + 200 },
+ { 240 - 104, 320 - 190, 240 + 104, 320 + 190 },
+ { 240 - 99, 320 - 180, 240 + 99, 320 + 180 },
+ { 240 - 93, 320 - 170, 240 + 93, 320 + 170 },
+ { 240 - 88, 320 - 160, 240 + 88, 320 + 160 },
+ { 240 - 82, 320 - 150, 240 + 82, 320 + 150 },
+ { 240 - 77, 320 - 140, 240 + 77, 320 + 140 },
+ { 240 - 71, 320 - 130, 240 + 71, 320 + 130 },
+ { 240 - 66, 320 - 120, 240 + 66, 320 + 120 },
+ { 240 - 60, 320 - 110, 240 + 60, 320 + 110 },
+ { 240 - 55, 320 - 100, 240 + 55, 320 + 100 },
+ { 240 - 49, 320 - 90, 240 + 49, 320 + 90 },
+ { 240 - 44, 320 - 80, 240 + 44, 320 + 80 },
+ { 240 - 38, 320 - 70, 240 + 38, 320 + 70 },
+ { 240 - 33, 320 - 60, 240 + 33, 320 + 60 },
+ { 240 - 27, 320 - 50, 240 + 27, 320 + 50 },
+ { 240 - 22, 320 - 40, 240 + 22, 320 + 40 } }
+ };
+
+ int colorInt, shading;
+ float colorFrac, nColorFrac;
+ MRect newRect;
+ SDL_Rect sdlRect;
+
+ if( *target > 18 )
+ {
+ *target = 18;
+ animationStageComplete = true;
+ }
+
+ colorInt = (int) floor( *colorWrap );
+ colorFrac = *colorWrap - colorInt;
+
+ newRect = larger? largerRect[animationType][*target]: normalRect[animationType][*target];
+ shading = ((animationType == 0) ? (*target * 24 / 18): (24 - (*target * 2 / 3)));
+
+ {
+ float r1 = backColor[colorInt ].red, g1 = backColor[colorInt ].green, b1 = backColor[colorInt ].blue,
+ r2 = backColor[(colorInt+1)&3].red, g2 = backColor[(colorInt+1)&3].green, b2 = backColor[(colorInt+1)&3].blue,
+ r3 = backColor[(colorInt+2)&3].red, g3 = backColor[(colorInt+2)&3].green, b3 = backColor[(colorInt+2)&3].blue,
+ r4 = backColor[(colorInt+3)&3].red, g4 = backColor[(colorInt+3)&3].green, b4 = backColor[(colorInt+3)&3].blue;
+
+ nColorFrac = 1 - colorFrac;
+
+ SDLU_AcquireSurface( drawSurface );
+
+ SurfaceBlitBlendOver( backSurface, drawSurface,
+ &newRect, &newRect,
+ (int)((r1 * nColorFrac) + (r2 * colorFrac)),
+ (int)((g1 * nColorFrac) + (g2 * colorFrac)),
+ (int)((b1 * nColorFrac) + (b2 * colorFrac)),
+ (int)((r2 * nColorFrac) + (r3 * colorFrac)),
+ (int)((g2 * nColorFrac) + (g3 * colorFrac)),
+ (int)((b2 * nColorFrac) + (b3 * colorFrac)),
+ (int)((r4 * nColorFrac) + (r1 * colorFrac)),
+ (int)((g4 * nColorFrac) + (g1 * colorFrac)),
+ (int)((b4 * nColorFrac) + (b1 * colorFrac)),
+ (int)((r3 * nColorFrac) + (r4 * colorFrac)),
+ (int)((g3 * nColorFrac) + (g4 * colorFrac)),
+ (int)((b3 * nColorFrac) + (b4 * colorFrac)),
+ _5TO8(shading) );
+
+ if( pauseRect->left < newRect.left )
+ {
+ MRect eraseRect = *pauseRect;
+ pauseRect->left = eraseRect.right = newRect.left;
+
+ SDLU_MRectToSDLRect( &eraseRect, &sdlRect );
+ SDLU_BlitSurface( backSurface, &sdlRect,
+ drawSurface, &sdlRect );
+ }
+
+ if( pauseRect->right > newRect.right )
+ {
+ MRect eraseRect = *pauseRect;
+ pauseRect->right = eraseRect.left = newRect.right;
+
+ SDLU_MRectToSDLRect( &eraseRect, &sdlRect );
+ SDLU_BlitSurface( backSurface, &sdlRect,
+ drawSurface, &sdlRect );
+ }
+
+ if( pauseRect->top < newRect.top )
+ {
+ MRect eraseRect = *pauseRect;
+ pauseRect->top = eraseRect.bottom = newRect.top;
+
+ SDLU_MRectToSDLRect( &eraseRect, &sdlRect );
+ SDLU_BlitSurface( backSurface, &sdlRect,
+ drawSurface, &sdlRect );
+ }
+
+ if( pauseRect->bottom > newRect.bottom )
+ {
+ MRect eraseRect = *pauseRect;
+ pauseRect->bottom = eraseRect.top = newRect.bottom;
+
+ SDLU_MRectToSDLRect( &eraseRect, &sdlRect );
+ SDLU_BlitSurface( backSurface, &sdlRect,
+ drawSurface, &sdlRect );
+ }
+
+ SDLU_ReleaseSurface( drawSurface );
+ }
+
+ *pauseRect = newRect;
+
+ *colorWrap += colorInc * skip;
+ if( *colorWrap >= 4 ) *colorWrap -= 4;
+
+ *target += skip;
+
+ return animationStageComplete;
+}
+
+#if USE_CURSOR_SPRITE
+static void DrawDialogCursor( MRect *pauseRect, int *shade )
+{
+ MPoint p, q;
+ (void) shade;
+
+ SDLU_GetMouse( &p );
+
+ if( p.h < (pauseRect->left ) ) p.h = pauseRect->left;
+ if( p.h > (pauseRect->right - 5) ) p.h = pauseRect->right - 5;
+ if( p.v < (pauseRect->top ) ) p.v = pauseRect->top;
+ if( p.v > (pauseRect->bottom - 5) ) p.v = pauseRect->bottom - 5;
+ q = p;
+
+ SDLU_AcquireSurface( drawSurface );
+
+ SurfaceBlitCharacter( smallFont, '\x05', &p, 0, 0, 0, 0 );
+ SurfaceBlitCharacter( smallFont, '\x04', &q, 255, 255, 255, 0 );
+
+ SDLU_ReleaseSurface( drawSurface );
+}
+#endif
+
+static void DrawDialogLogo( MRect *pauseRect, int shade )
+{
+ MRect drawRect;
+ int alpha;
+
+ drawRect.left = (pauseRect->left + ((pauseRect->right - pauseRect->left) * 1 / 2) ) - (logoRect.right / 2);
+ drawRect.top = (pauseRect->top + 14);
+ drawRect.bottom = drawRect.top + logoRect.bottom;
+ drawRect.right = drawRect.left + logoRect.right;
+
+ SDLU_AcquireSurface( drawSurface );
+
+ alpha = (shade > 63)? 255: (shade * 4);
+
+ SurfaceBlitWeightedDualAlpha( drawSurface, logoSurface, logoMaskSurface, logoAlphaSurface, drawSurface,
+ &drawRect, &logoRect, &logoRect, &logoRect, &drawRect,
+ alpha );
+
+ SDLU_ReleaseSurface( drawSurface );
+}
+
+
+enum
+{
+ kNothing = -1,
+ kBack = -2,
+
+// main pause screen (kEndGame is reused in continue and register)
+ kMusic = 0, kResume,
+ kSound, kEndGame,
+ kVideo, kControls,
+ kWarp,
+
+// continue screen
+ kContinue,
+
+// controls screen
+ k1PLeft, k2PLeft,
+ k1PRight, k2PRight,
+ k1PDrop, k2PDrop,
+ k1PRotate, k2PRotate,
+ kControlsOK, kControlsReset,
+
+// video settings screen
+ kFullscreen,
+ kWidescreen,
+ kScalingMode,
+ kVideoOK,
+};
+
+static void DrawContinueContents( int *item, int shade )
+{
+ char line[4][50] = { "Do you want to continue?",
+ "Yes",
+ "No",
+ "" };
+ MPoint dPoint[4] = { {233, 210}, {280, 220}, {280, 400}, {335, 400} }, hPoint = {255, 320};
+ static int lastCountdown = 0;
+ int index, countdown, fade;
+ int r, g, b;
+
+ sprintf( line[3], "%d credit%c", credits, (credits != 1)? 's': ' ' );
+
+ SDLU_AcquireSurface( drawSurface );
+
+ for( index=0; index<4; index++ )
+ {
+ DrawRainbowText( smallFont, line[index], dPoint[index], (0.25 * index) + (0.075 * shade),
+ ( (index == 0) ||
+ ((index == 1) && (*item == kContinue)) ||
+ ((index == 2) && (*item == kEndGame )) )? kTextBrightRainbow: kTextRainbow );
+ }
+
+ countdown = shade / 100;
+ if( countdown < 10 )
+ {
+ continueTimeOut = false;
+
+ if( (countdown != 0) && (countdown != lastCountdown) )
+ {
+ PlayMono( kContinueSnd );
+ }
+ lastCountdown = countdown;
+
+ if( countdown < 5 )
+ {
+ r = (countdown * 31) / 5;
+ g = 31;
+ }
+ else
+ {
+ r = 31;
+ g = ((10 - countdown) * 31) / 5;
+ }
+
+ fade = shade % 100;
+ if( fade > 50 ) fade = 50;
+ r = ((31 * (49 - fade)) + (r * fade)) / 49;
+ g = ((31 * (49 - fade)) + (g * fade)) / 49;
+ b = ((31 * (49 - fade))) / 49;
+
+ countdown = '9' - countdown;
+ hPoint.h -= continueFont->width[countdown] / 2;
+
+ for( shade = 4; shade > 0; shade-- )
+ {
+ MPoint hP = hPoint;
+
+ hP.h += 2 * shade;
+ hP.v += 2 * shade;
+
+ int weight = 20 - 4*shade;
+
+ SurfaceBlitWeightedCharacter( continueFont, countdown, &hP, 0, 0, 0, _5TO8(weight) );
+ }
+
+ SurfaceBlitCharacter( continueFont, countdown, &hPoint, _5TO8(r), _5TO8(g), _5TO8(b), 0 );
+ }
+ else
+ {
+ continueTimeOut = true;
+ }
+
+ SDLU_ReleaseSurface( drawSurface );
+}
+
+static void DrawHiScoreContents( int *item, int shade )
+{
+ MPoint dPoint[3] = { {240, 640}, {260, 640}, {335, 400} }, hPoint = {294, 145};
+ MPoint dashedLinePoint = { 320, 140 };
+ int index;
+ int nameLength;
+ const char* line[3];
+ const char* scan;
+
+ (void) item; // is unused
+
+ line[0] = highScoreText;
+ line[1] = "Please enter your name and press return:";
+ line[2] = highScoreRank;
+
+ for( index=0; index<2; index++ )
+ {
+ scan = line[index];
+ while( *scan )
+ dPoint[index].h -= smallFont->width[(uint8_t) * scan++];
+
+ dPoint[index].h /= 2;
+ }
+
+ SDLU_AcquireSurface( drawSurface );
+
+ while( dashedLinePoint.h < 490 )
+ {
+ SurfaceBlitCharacter( dashedLineFont, '.', &dashedLinePoint, 0, 0, 0, 0 );
+ }
+
+ nameLength = (int) strlen(highScoreName);
+ for( index = 0; index < nameLength; index++ )
+ {
+ SurfaceBlitCharacter( bigFont, highScoreName[index], &hPoint, 255, 255, 255, 1 );
+ if( hPoint.h >= 475 )
+ {
+ highScoreName[index] = '\0';
+ break;
+ }
+ }
+
+ index = (int)(( 1.0 + sin( MTickCount() / 7.5 ) ) * 120.0);
+ SurfaceBlitCharacter( bigFont, '|', &hPoint, index, index, 255, 1 );
+
+ for( index=0; index<3; index++ )
+ {
+ DrawRainbowText( smallFont, line[index], dPoint[index], (0.25 * index) + (0.075 * shade), (index != 2)? kTextBrightRainbow: kTextRainbow );
+ }
+
+ SDLU_ReleaseSurface( drawSurface );
+}
+
+static void DrawControlsContents( int *item, int shade )
+{
+ MBoolean highlight;
+ MPoint dPoint;
+ int index;
+ const char* controlName;
+ int r, g, b;
+ const char label[8][20] = { "1P Left", "2P Left",
+ "1P Right", "2P Right",
+ "1P Drop", "2P Drop",
+ "1P Rotate", "2P Rotate" };
+
+
+ SDLU_AcquireSurface( drawSurface );
+
+ for( index=0; index<8; index++ )
+ {
+ highlight = (index == (*item - k1PLeft));
+
+ dPoint.v = 229 + ((index & ~1) * 13);
+ dPoint.h = (index & 1)? 325: 130;
+ DrawRainbowText( smallFont, label[index], dPoint, (0.25 * index) + (0.075 * shade), highlight? kTextBrightRainbow: kTextRainbow );
+
+ dPoint.v = 245 + ((index & ~1) * 13);
+ dPoint.h = (index & 1)? 420: 225;
+
+ r = highlight? 255: 0;
+ g = b = (int)(highlight? 255.0 - (88.0 * (sin(shade * 0.2) + 1.0)): 0.0);
+
+ SurfaceBlitCharacter( dashedLineFont, '.', &dPoint, r, g, b, 0 );
+ SurfaceBlitCharacter( dashedLineFont, '.', &dPoint, r, g, b, 0 );
+ SurfaceBlitCharacter( dashedLineFont, '.', &dPoint, r, g, b, 0 );
+ SurfaceBlitCharacter( dashedLineFont, '.', &dPoint, r, g, b, 0 );
+ SurfaceBlitCharacter( dashedLineFont, '.', &dPoint, r, g, b, 0 ); // 80 pixels across
+
+ controlName = SDL_GetKeyName( playerKeys[index & 1][index >> 1] );
+ if( controlName == NULL ) controlName = "???";
+
+ dPoint.v = 231 + ((index & ~1) * 13);
+ dPoint.h = (index & 1)? 460: 265;
+ dPoint.h -= GetTextWidth( tinyFont, controlName ) / 2;
+ DrawRainbowText( tinyFont, controlName, dPoint, (0.1 * shade), (controlToReplace == index)? kTextBlueGlow: kTextWhite );
+ }
+
+ dPoint.h = 200;
+ dPoint.v = 340;
+ DrawRainbowText( smallFont, "\x03 OK", dPoint, 8.0 + (0.075 * shade), (*item == kControlsOK)? kTextBrightRainbow: kTextRainbow );
+
+ dPoint.h = 365;
+ dPoint.v = 340;
+ DrawRainbowText( smallFont, "\x03 Reset", dPoint, 8.25 + (0.075 * shade), (*item == kControlsReset)? kTextBrightRainbow: kTextRainbow );
+
+ SDLU_ReleaseSurface( drawSurface );
+}
+
+static void DrawPauseContents( int *item, int shade )
+{
+ const char *line[] =
+ {
+ musicOn ? "\x01 Music" : "\x02 Music",
+ level == kTutorialLevel ? "\x03 Skip Tutorial" : "\x03 Resume",
+ soundOn ? "\x01 Sound" : "\x02 Sound",
+ "\x03 End Game",
+ "\x03 Video",
+ "\x03 Controls",
+ };
+
+ SDLU_AcquireSurface( drawSurface );
+
+ for( int i = 0; i < arrsize(line); i++ )
+ {
+ MPoint dPoint;
+ dPoint.h = (i & 1)? 340: 180;
+ dPoint.v = 240 + ((i & ~1) * 15);
+
+ DrawRainbowText( smallFont, line[i], dPoint, (0.25 * i) + (0.075 * shade), (*item == i)? kTextBrightRainbow: kTextRainbow );
+ }
+
+ SDLU_ReleaseSurface( drawSurface );
+}
+
+static void DrawVideoSettingsContents(int* item, int shade)
+{
+ struct ZoneLabel
+ {
+ int item;
+ const char* text;
+ }
+ labels[] =
+ {
+ { kFullscreen, fullscreen ? "\x01 Fullscreen" : "\x02 Fullscreen" },
+ { kWidescreen, widescreen ? "\x01 Widescreen" : "\x02 Widescreen" },
+ { kScalingMode, crispUpscaling ? "\x01 Crisp upscaling" : "\x02 Crisp upscaling" },
+ { kVideoOK, "\x03 OK" },
+ };
+
+ SDLU_AcquireSurface(drawSurface);
+
+ for (int i = 0; i < arrsize(labels); i++)
+ {
+ MPoint dPoint;
+ dPoint.h = 180;
+ dPoint.v = 240 + (i * 30);
+
+ DrawRainbowText(smallFont, labels[i].text, dPoint, (0.25 * i) + (0.075 * shade), (*item == labels[i].item) ? kTextBrightRainbow : kTextRainbow);
+ }
+
+ SDLU_ReleaseSurface(drawSurface);
+}
+
+static MBoolean GetClickedZone( int* item, SDL_Keycode inSDLKey, int numZones, const ClickableZone* zones )
+{
+ if( inSDLKey == SDLK_ESCAPE )
+ {
+ *item = kBack;
+ return true;
+ }
+
+ MPoint p;
+ SDLU_GetMouse(&p);
+
+ int trigger = SDLU_Button();
+
+ *item = kNothing;
+ for( int i = 0; i < numZones; i++ )
+ {
+ if( MPointInMRect( p, &zones[i].rect ) )
+ {
+ *item = zones[i].item;
+ }
+ }
+
+ return trigger;
+}
+
+
+static MBoolean ContinueSelected( int *item, unsigned char inKey, SDL_Keycode inSDLKey )
+{
+ static const ClickableZone zones[] =
+ {
+ { kContinue, {280, 220, 300, 260} },
+ { kEndGame, {280, 400, 300, 440} },
+ };
+
+ (void) inSDLKey; // is unused
+
+ if( continueTimeOut )
+ {
+ *item = kEndGame;
+ return true;
+ }
+
+ int trigger = GetClickedZone( item, inSDLKey, arrsize(zones), zones );
+
+ if (trigger && *item == kBack)
+ *item = kContinue;
+
+ return trigger && *item != kNothing;
+}
+
+static MBoolean HiScoreSelected( int *item, unsigned char inKey, SDL_Keycode inSDLKey )
+{
+ int nameLength = (int) strlen(highScoreName);
+
+ // return (SDL key)
+ if( inSDLKey == SDLK_RETURN )
+ {
+ if( nameLength > 0 )
+ {
+ *item = kResume;
+ PlayMono( kSquishy );
+ return true;
+ }
+ else
+ {
+ PlayMono( kClick );
+ }
+ }
+
+ // backspace (SDL key)
+ if( inSDLKey == SDLK_BACKSPACE )
+ {
+ if( nameLength > 0 )
+ {
+ highScoreName[ nameLength-1 ] = '\0';
+ PlayMono( kClick );
+ }
+ }
+
+ // characters (ASCII key!)
+ if( bigFont->width[inKey] != 0 )
+ {
+ highScoreName[ nameLength++ ] = inKey;
+ highScoreName[ nameLength ] = '\0';
+ PlayMono( kPlace );
+ }
+
+ *item = kNothing;
+ return false;
+}
+
+
+static MBoolean ControlsSelected( int *item, unsigned char inKey, SDL_Keycode inSDLKey )
+{
+ MPoint p;
+ MRect dRect;
+ int index;
+ static MBoolean lastDown = false;
+ MBoolean down;
+ int returnValue = 0;
+
+ static const ClickableZone buttonZones[] =
+ {
+ { kControlsOK, { 340, 200, 360, 255 } },
+ { kControlsReset, { 340, 365, 360, 450 } },
+ };
+
+ (void) inKey; // unused
+
+ *item = kNothing;
+
+
+ down = GetClickedZone( item, inSDLKey, arrsize(buttonZones), buttonZones );
+
+ if ( down && *item != kNothing )
+ {
+ if (!lastDown)
+ {
+ switch (*item)
+ {
+ case kBack:
+ case kControlsOK:
+ PlayMono(kClick);
+ returnValue = 1;
+ controlToReplace = -1;
+ break;
+
+ case kControlsReset:
+ PlayMono(kClick);
+ memcpy(playerKeys, defaultPlayerKeys, sizeof(playerKeys));
+ break;
+ }
+ }
+ }
+ else
+ {
+ SDLU_GetMouse(&p);
+
+ for( index=0; index<8; index++ )
+ {
+ dRect.top = 229 + ((index & ~1) * 13);
+ dRect.left = (index & 1)? 325: 130;
+ dRect.bottom = dRect.top + 24;
+ dRect.right = dRect.left + 175;
+
+ if( MPointInMRect( p, &dRect ) )
+ {
+ *item = k1PLeft + index;
+ if( down && !lastDown && !AnyKeyIsPressed() )
+ {
+ controlToReplace = (controlToReplace == index)? -1: index;
+ }
+ break;
+ }
+ }
+ }
+
+ if( inSDLKey != 0 && controlToReplace != -1 )
+ {
+ playerKeys[controlToReplace & 1][controlToReplace >> 1] = inSDLKey;
+ controlToReplace = -1;
+ }
+
+ lastDown = down;
+
+ return returnValue;
+}
+
+
+static MBoolean PauseSelected( int *item, unsigned char inKey, SDL_Keycode inSDLKey )
+{
+ (void) inSDLKey; // is unused
+
+ static const ClickableZone zones[] =
+ {
+ { kMusic, { 240, 180, 260, 320 } }, { kResume, { 240, 340, 260, 480 } },
+ { kSound, { 270, 180, 290, 320 } }, { kEndGame, { 270, 340, 290, 480 } },
+ { kVideo, { 300, 180, 320, 320 } }, { kControls, { 300, 340, 320, 480 } },
+ { kWarp, { 330, 180, 350, 320 } },
+ };
+
+ static MBoolean lastDown = false;
+
+ int trigger = GetClickedZone( item, inSDLKey, arrsize(zones), zones );
+
+ if( trigger )
+ {
+ if( !lastDown )
+ {
+ lastDown = true;
+
+ switch( *item )
+ {
+ case kSound:
+ PlayMono( kClick );
+ soundOn = !soundOn;
+ PlayMono( kClick );
+ return false;
+
+ case kMusic:
+ PlayMono( kClick );
+ musicOn = !musicOn;
+ EnableMusic( musicOn );
+ return false;
+
+ case kFullscreen:
+ fullscreen = !fullscreen;
+ SetFullscreen( fullscreen );
+ PlayMono( kClick );
+ return false;
+
+ case kScalingMode:
+ crispUpscaling = !crispUpscaling;
+ SDLU_CreateRendererTexture();
+ PlayMono(kClick);
+ return false;
+
+ case kEndGame:
+ case kResume:
+ case kBack:
+ case kControls:
+ case kVideo:
+ PlayMono( kClick );
+ return true;
+
+ case kWarp:
+ if( ControlKeyIsPressed( ) )
+ {
+ PlayMono(kLevelUp);
+ level++; //Warp( );
+ return true;
+ }
+ else
+ {
+ *item = kNothing;
+ }
+ return false;
+ }
+ }
+ }
+ else
+ {
+ lastDown = false;
+ }
+
+ return false;
+}
+
+
+
+static MBoolean VideoSettingsSelected( int *item, unsigned char inKey, SDL_Keycode inSDLKey )
+{
+ (void) inSDLKey; // is unused
+
+ static const ClickableZone zones[] =
+ {
+ { kFullscreen, { 240, 180, 260, 320 } },
+ { kWidescreen, { 270, 180, 290, 320 } },
+ { kScalingMode, { 300, 180, 320, 320 } },
+ { kVideoOK, { 330, 180, 350, 320 } },
+ };
+
+ static MBoolean lastDown = false;
+
+ int trigger = GetClickedZone( item, inSDLKey, arrsize(zones), zones );
+
+ if( trigger )
+ {
+ if( !lastDown )
+ {
+ lastDown = true;
+
+ switch( *item )
+ {
+ case kNothing:
+ break;
+
+ case kFullscreen:
+ fullscreen = !fullscreen;
+ SetFullscreen( fullscreen );
+ PlayMono( kClick );
+ return false;
+
+ case kScalingMode:
+ crispUpscaling = !crispUpscaling;
+ SDLU_CreateRendererTexture();
+ PlayMono(kClick);
+ return false;
+
+ case kWidescreen:
+ widescreen= !widescreen;
+ ResetWidescreenLayout();
+ SDLU_CreateRendererTexture();
+ SetFullscreen(fullscreen);
+ PlayMono(kClick);
+
+ NeedRefresh();
+ //RefreshAll();
+ //RefreshPlayerWindow(0);
+ //RefreshPlayerWindow(1);
+
+ return false;
+
+ default:
+ PlayMono( kClick );
+ return true;
+ }
+ }
+ }
+ else
+ {
+ lastDown = false;
+ }
+
+ return false;
+}
+
+void HandleDialog( int type )
+{
+ const float lighten[4] = { 96.0f, 48.0f, 8.0f, 48.0f };
+ const MRect boardWorldZRect = {0, 0, kBlobVertSize * (kGridDown-1), kBlobHorizSize * kGridAcross};
+ SDL_Rect fullSDLRect = { 0, 0, 640, 480 };
+ SDL_Rect joinSDLRect;
+ int skip = 1;
+ int count;
+ char inASCII;
+ SDL_Keycode inSDLKey;
+ MRect pauseRect, joinRect;
+
+ // Clear state
+ whichField = nameField;
+ nameField[0] = '\0';
+ keyField[0] = '\0';
+ batsuAlpha = 0;
+ controlToReplace = -1;
+
+ // Remember dialog info
+ dialogType = type;
+ dialogStage = kOpening;
+ colorWrap = 0;
+ colorInc = (RandomBefore(250) + 250.0) / 10000.0;
+
+ smallFont = GetFont( picFont );
+ tinyFont = GetFont( picTinyFont );
+ bigFont = GetFont( picHiScoreFont );
+ dashedLineFont = GetFont( picDashedLineFont );
+ continueFont = GetFont( picContinueFont );
+ batsuFont = GetFont( picBatsuFont );
+
+ // Pick some colors to animate.
+ for( count=0; count<4; count++ )
+ {
+ SDL_Color inColor;
+
+ SDLU_GetPixel( boardSurface[0], RandomBefore( boardWorldZRect.right ), RandomBefore( boardWorldZRect.bottom ), &inColor );
+
+ backColor[count].red = MinInt( 255.0f, inColor.r + lighten[count] );
+ backColor[count].green = MinInt( 255.0f, inColor.g + lighten[count] );
+ backColor[count].blue = MinInt( 255.0f, inColor.b + lighten[count] );
+ }
+
+ // Get some graphics that we're going to need
+ logoSurface = LoadPICTAsSurface( picLogo, 32 );
+ logoAlphaSurface = LoadPICTAsSurface( picLogoAlpha, 32 );
+ logoMaskSurface = LoadPICTAsSurface( picLogoMask, MASK_DEPTH );
+
+ // Get a copy of the current game window contents
+ backSurface = SDLU_InitSurface( &fullSDLRect, 32 );
+
+ SDLU_BlitSurface( g_frontSurface, &g_frontSurface->clip_rect,
+ backSurface, &backSurface->clip_rect );
+
+ drawSurface = SDLU_InitSurface( &fullSDLRect, 32 );
+
+ SDLU_BlitSurface( backSurface, &backSurface->clip_rect,
+ drawSurface, &drawSurface->clip_rect );
+
+ //
+
+ PlayMono( kWhomp );
+ dialogTimer = MTickCount();
+ dialogTarget = 0;
+ dialogShade = 0;
+ dialogStageComplete = false;
+ dialogItem = kNothing;
+ lastPauseRect.top = lastPauseRect.left = 9999;
+ lastPauseRect.bottom = lastPauseRect.right = -9999;
+
+ SDLU_StartWatchingTyping();
+
+ DoFullRepaint = ItsTimeToRedraw;
+
+ while( ((dialogStage != kClosing) || !dialogStageComplete) && !finished )
+ {
+ dialogTimer += skip;
+
+ UpdateSound();
+
+ // Check mouse and keyboard
+ SDLU_CheckASCIITyping( &inASCII );
+ SDLU_CheckSDLTyping( &inSDLKey );
+
+ if( (dialogStage == kOpening) && dialogStageComplete )
+ {
+ MBoolean (*DialogSelected[kNumDialogs])( int *item, unsigned char inKey, SDL_Keycode inSDLKey ) =
+ {
+ PauseSelected,
+ HiScoreSelected,
+ ContinueSelected,
+ ControlsSelected,
+ VideoSettingsSelected,
+ };
+
+ if( DialogSelected[dialogType]( &dialogItem, inASCII, inSDLKey ) )
+ {
+ SDLU_SetSystemCursor( SYSTEM_CURSOR_OFF );
+
+ dialogStage = kClosing;
+ dialogTarget = 0;
+ }
+ }
+
+ // Do animation ...
+ {
+ MBoolean dialogIsLarge = dialogType == kControlsDialog;
+
+ pauseRect = lastPauseRect;
+ dialogStageComplete = DrawDialogBox( dialogIsLarge, dialogStage, &dialogTarget, skip, &colorWrap, colorInc, &pauseRect );
+ SurfaceGetEdges( backSurface, &pauseRect );
+ }
+
+ if( (dialogStage == kOpening) && dialogStageComplete )
+ {
+ void (*DialogDraw[kNumDialogs])( int *item, int shade ) =
+ {
+ DrawPauseContents,
+ DrawHiScoreContents,
+ DrawContinueContents,
+ DrawControlsContents,
+ DrawVideoSettingsContents,
+ };
+
+ // Refresh screen if necessary
+ if( timeToRedraw )
+ {
+ SDLU_BlitFrontSurface( backSurface, &fullSDLRect, &fullSDLRect );
+
+ timeToRedraw = false;
+ }
+
+ // ... and fade in the logo
+
+ dialogShade += skip;
+
+ {
+ bool dialogHasCandyCrisisLogo = true;
+
+ if( dialogHasCandyCrisisLogo )
+ DrawDialogLogo( &pauseRect, dialogShade );
+ }
+
+ // ... and animation is complete so add content
+ DialogDraw[dialogType]( &dialogItem, dialogShade );
+
+#if USE_CURSOR_SPRITE
+ // ... and cursor
+ DrawDialogCursor( &pauseRect, &dialogShade );
+#endif
+ SDLU_SetSystemCursor( dialogItem == kNothing ? SYSTEM_CURSOR_ARROW : SYSTEM_CURSOR_HAND );
+ }
+
+ SurfaceCurveEdges( drawSurface, &pauseRect );
+
+ // Draw new animation on screen
+ UnionMRect( &lastPauseRect, &pauseRect, &joinRect );
+ SDLU_MRectToSDLRect( &joinRect, &joinSDLRect );
+ SDLU_BlitFrontSurface( drawSurface, &joinSDLRect, &joinSDLRect );
+ SDLU_Present();
+
+ lastPauseRect = pauseRect;
+
+ // Wait for next frame
+ if( dialogTimer <= MTickCount( ) )
+ {
+ dialogTimer = MTickCount( );
+ skip = 2;
+ }
+ else
+ {
+ skip = 1;
+ while( dialogTimer > MTickCount( ) )
+ {
+ SDLU_Yield();
+ }
+ }
+ }
+
+ DoFullRepaint = NoPaint;
+
+ SDLU_StopWatchingTyping();
+
+ // Bring back previous screen
+ SDLU_BlitFrontSurface( backSurface, &fullSDLRect, &fullSDLRect );
+ SDLU_Present();
+
+ // Dispose the GWorlds and fonts we used
+ SDL_FreeSurface( backSurface );
+ SDL_FreeSurface( drawSurface );
+ SDL_FreeSurface( logoSurface );
+ SDL_FreeSurface( logoAlphaSurface );
+ SDL_FreeSurface( logoMaskSurface );
+
+ switch( dialogItem )
+ {
+ case kVideo:
+ HandleDialog( kVideoDialog );
+ HandleDialog( kPauseDialog );
+ break;
+
+ case kControls:
+ HandleDialog( kControlsDialog );
+ HandleDialog( kPauseDialog );
+ break;
+
+ case kEndGame:
+ ChooseMusic( -1 );
+ AddHiscore( score[0] );
+ if( players == 1 )
+ {
+ ShowGameOverScreen( );
+ }
+ else
+ {
+ QuickFadeOut(NULL);
+ }
+
+ showStartMenu = true;
+ break;
+
+ case kContinue:
+ displayedScore[0] = score[0] = roundStartScore[0];
+ ShowScore( 0 );
+ BeginRound( true );
+ break;
+
+ case kWarp:
+ {
+ int newLevel = level;
+
+ InitGame( OptionKeyIsPressed()? kAIControl: kPlayerControl, kAIControl ); // this clears "level" ...
+ level = newLevel; // so we need to set "level" afterwards
+ BeginRound( true );
+ break;
+ }
+ }
+}
--- a/src/pause.cpp
+++ /dev/null
@@ -1,1338 +1,0 @@
-// pause.cpp
-
-// All of this code is fugly. I really needed a dialog manager, but I didn't know it at the time,
-// and instead I cobbled this together. It is just barely good enough to work. Fortunately it looks
-// decent to the end user...
-
-
-#include "SDLU.h"
-
-#include <algorithm>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-
-#include "main.h"
-#include "gameticks.h"
-#include "blitter.h"
-#include "graphics.h"
-#include "gworld.h"
-#include "pause.h"
-#include "random.h"
-#include "font.h"
-#include "music.h"
-#include "soundfx.h"
-#include "keyselect.h"
-#include "level.h"
-#include "victory.h"
-#include "hiscore.h"
-#include "score.h"
-
-using std::min;
-using std::max;
-
-struct FRGBColor
-{
- float red, green, blue;
-};
-
-struct ClickableZone
-{
- int item;
- MRect rect;
-};
-
-SDL_Surface* backSurface;
-SDL_Surface* drawSurface;
-SDL_Surface* logoSurface;
-SDL_Surface* logoMaskSurface;
-SDL_Surface* logoAlphaSurface;
-
-SkittlesFontPtr smallFont, bigFont, dashedLineFont, continueFont, tinyFont, batsuFont;
-FRGBColor backColor[4];
-MBoolean continueTimeOut;
-
-static int dialogType, dialogStage, dialogTarget, dialogShade, dialogItem;
-MTicks dialogTimer;
-static float colorWrap = 0, colorInc;
-static MRect logoRect = {0, 0, 111, 246}, lastPauseRect;
-static MBoolean dialogStageComplete;
-static MBoolean timeToRedraw = false;
-
-// for the controls dialog
-static int controlToReplace = -1;
-
-// for the enter code dialog
-static char nameField[256], keyField[256];
-static char* whichField = nameField;
-static int batsuAlpha = 0;
-
-static void ItsTimeToRedraw()
-{
- timeToRedraw = true;
-}
-
-enum
-{
- kTextRainbow,
- kTextBrightRainbow,
- kTextWhite,
- kTextBlueGlow,
- kTextGray,
- kTextAlmostWhite
-};
-
-static MPoint DrawRainbowText( SkittlesFontPtr font, const char *line, MPoint dPoint, float wave, int bright )
-{
- int current;
- int r,g,b;
- float s;
-
- current = 0;
-
- switch( bright )
- {
- case kTextGray:
- r = g = b = 96;
- break;
-
- case kTextBlueGlow:
- s = sin(wave);
- r = (int)(88.0 + 120.0 * s * s);
- g = r;
- b = 255;
- break;
-
- case kTextWhite:
- r = g = b = 255;
- break;
-
- case kTextAlmostWhite:
- default:
- r = g = b = 224;
- break;
-
- }
-
- while( line[current] )
- {
- switch( bright )
- {
- case kTextBrightRainbow:
- r = (int)(208.0 + 40.0 * sin(wave ));
- g = (int)(208.0 + 40.0 * sin(wave + ((2.*pi) * 1./3.)));
- b = (int)(208.0 + 40.0 * sin(wave + ((2.*pi) * 2./3.)));
- break;
-
- case kTextRainbow:
- r = (int)(128.0 + 96.0 * sin(wave ));
- g = (int)(128.0 + 96.0 * sin(wave + ((2.*pi) * 1./3.)));
- b = (int)(128.0 + 96.0 * sin(wave + ((2.*pi) * 2./3.)));
- break;
- }
-
- SurfaceBlitCharacter( font, line[current], &dPoint, r, g, b, 1 );
-
- wave += 0.2;
- current++;
- }
-
- return dPoint;
-}
-
-
-#define kEdgeSize 8
-static COLOR_T edge[4][kEdgeSize][kEdgeSize];
-
-void SurfaceGetEdges( SDL_Surface* edgeSurface, const MRect *rect )
-{
- unsigned char* src[4];
- int srcRowBytes;
-
- src[0] = src[1] = src[2] = src[3] = (unsigned char*) edgeSurface->pixels;
- srcRowBytes = edgeSurface->pitch;
-
- src[0] += (srcRowBytes * (rect->top )) + ((rect->left ) * BYTES_PER_PIXEL);
- src[1] += (srcRowBytes * (rect->top )) + ((rect->right - kEdgeSize) * BYTES_PER_PIXEL);
- src[2] += (srcRowBytes * (rect->bottom - kEdgeSize)) + ((rect->left ) * BYTES_PER_PIXEL);
- src[3] += (srcRowBytes * (rect->bottom - kEdgeSize)) + ((rect->right - kEdgeSize) * BYTES_PER_PIXEL);
-
- for (int count=0; count<4; count++)
- {
- for (int height=0; height<kEdgeSize; height++)
- {
- memcpy( edge[count][height], src[count], kEdgeSize * BYTES_PER_PIXEL );
- src[count] += srcRowBytes;
- }
- }
-}
-
-
-void SurfaceCurveEdges( SDL_Surface* edgeSurface, const MRect *rect )
-{
- unsigned char* src[4];
- int srcRowBytes, width, height, count;
- char edgeMap[4][kEdgeSize][kEdgeSize+1]={ " --",
- " -...",
- " -.xxX",
- " -.xXXX",
- " -.xXXXX",
- " .xXXXXX",
- "-.xXXXXX",
- "-.XXXXXX",
- "-- ",
- "...- ",
- "Xxx.- ",
- "XXXx.- ",
- "XXXXx.- ",
- "XXXXXx. ",
- "XXXXXx.-",
- "XXXXXX.-",
- "-.XXXXXX",
- "-.xXXXXX",
- " .xXXXXX",
- " -.xXXXX",
- " -.xXXX",
- " -.xxX",
- " -...",
- " --",
- "XXXXXX.-",
- "XXXXXx.-",
- "XXXXXx. ",
- "XXXXx.- ",
- "XXXx.- ",
- "Xxx.- ",
- "...- ",
- "-- " };
-
-
- src[0] = src[1] = src[2] = src[3] = (unsigned char*) edgeSurface->pixels;
- srcRowBytes = edgeSurface->pitch;
-
- src[0] += (srcRowBytes * (rect->top )) + ((rect->left ) * BYTES_PER_PIXEL);
- src[1] += (srcRowBytes * (rect->top )) + ((rect->right - kEdgeSize) * BYTES_PER_PIXEL);
- src[2] += (srcRowBytes * (rect->bottom - kEdgeSize)) + ((rect->left ) * BYTES_PER_PIXEL);
- src[3] += (srcRowBytes * (rect->bottom - kEdgeSize)) + ((rect->right - kEdgeSize) * BYTES_PER_PIXEL);
-
- const int HALFBRIGHT_MASK =
- (CHANNEL_MASK >> 1)
- | ((CHANNEL_MASK >> 1) << BITS_PER_1CHANNEL)
- | ((CHANNEL_MASK >> 1) << BITS_PER_2CHANNELS);
-
- // Draw top/bottom border
- {
- COLOR_T *srcT1 = (COLOR_T*) (src[0]) + kEdgeSize;
- COLOR_T *srcB1 = (COLOR_T*) (src[2] + (srcRowBytes*(kEdgeSize-1))) + kEdgeSize;
- COLOR_T *srcT2 = srcT1 + (srcRowBytes / BYTES_PER_PIXEL);
- COLOR_T *srcB2 = srcB1 - (srcRowBytes / BYTES_PER_PIXEL);
-
- for( width = rect->right - rect->left - (kEdgeSize * 2); width > 0; width-- )
- {
- *srcT1 = 0; srcT1++;
- *srcB1 = 0; srcB1++;
- *srcT2 = (*srcT2 >> 1) & HALFBRIGHT_MASK; srcT2++;
- *srcB2 = (*srcB2 >> 1) & HALFBRIGHT_MASK; srcB2++;
- }
- }
-
- // Draw left/right border
- {
- unsigned char *srcL1 = (src[0] + (srcRowBytes * kEdgeSize));
- unsigned char *srcR1 = (src[1] + (srcRowBytes * kEdgeSize)) + BYTES_PER_PIXEL * (kEdgeSize-1);
-
- unsigned char *srcL2 = srcL1 + BYTES_PER_PIXEL;
- unsigned char *srcR2 = srcR1 - BYTES_PER_PIXEL;
-
- for( height = rect->bottom - rect->top - (kEdgeSize * 2); height > 0; height-- )
- {
- *(COLOR_T*)srcL1 = 0;
- *(COLOR_T*)srcR1 = 0;
- *(COLOR_T*)srcL2 = (*(COLOR_T*)srcL2 >> 1) & HALFBRIGHT_MASK;
- *(COLOR_T*)srcR2 = (*(COLOR_T*)srcR2 >> 1) & HALFBRIGHT_MASK;
-
- srcL1 += srcRowBytes;
- srcR1 += srcRowBytes;
- srcL2 += srcRowBytes;
- srcR2 += srcRowBytes;
- }
- }
-
- // Draw curved edges
- for( count=0; count<4; count++ )
- {
- COLOR_T *srcS = (COLOR_T*) src[count];
-
- for( height=0; height<kEdgeSize; height++ )
- {
- for( width=0; width<kEdgeSize; width++ )
- {
- switch( edgeMap[count][height][width] )
- {
- case ' ': *srcS = edge[count][height][width]; break;
- case '-': *srcS = (edge[count][height][width] >> 1) & HALFBRIGHT_MASK; break;
- case '.': *srcS = 0; break;
- case 'x': *srcS = (*srcS >> 1) & HALFBRIGHT_MASK; break;
- case 'X': break;
- }
- srcS++;
- }
- srcS += (srcRowBytes / BYTES_PER_PIXEL) - kEdgeSize;
- }
- }
-}
-
-enum
-{
- kOpening = 0,
- kClosing
-};
-
-static MBoolean DrawDialogBox( MBoolean larger, int animationType, int *target, int skip, float *colorWrap, float colorInc, MRect *pauseRect )
-{
- MBoolean animationStageComplete = false;
- MRect normalRect[2][19] = { { { 240 - 10, 320 - 30, 240 + 10, 320 + 30 },
- { 240 - 40, 320 - 120, 240 + 40, 320 + 120 },
- { 240 - 60, 320 - 180, 240 + 60, 320 + 180 },
- { 240 - 70, 320 - 210, 240 + 70, 320 + 210 },
- { 240 - 80, 320 - 230, 240 + 80, 320 + 230 },
- { 240 - 88, 320 - 245, 240 + 88, 320 + 245 },
- { 240 - 95, 320 - 252, 240 + 95, 320 + 252 },
- { 240 - 101, 320 - 255, 240 + 101, 320 + 255 },
- { 240 - 106, 320 - 252, 240 + 106, 320 + 252 },
- { 240 - 110, 320 - 245, 240 + 110, 320 + 245 },
- { 240 - 113, 320 - 238, 240 + 113, 320 + 238 },
- { 240 - 115, 320 - 232, 240 + 115, 320 + 232 },
- { 240 - 116, 320 - 228, 240 + 116, 320 + 228 },
- { 240 - 118, 320 - 232, 240 + 118, 320 + 230 },
- { 240 - 118, 320 - 238, 240 + 118, 320 + 232 },
- { 240 - 119, 320 - 242, 240 + 119, 320 + 242 },
- { 240 - 119, 320 - 244, 240 + 119, 320 + 244 },
- { 240 - 119, 320 - 242, 240 + 119, 320 + 242 },
- { 240 - 120, 320 - 240, 240 + 120, 320 + 240 } },
- { { 240 - 110, 320 - 220, 240 + 110, 320 + 220 },
- { 240 - 105, 320 - 210, 240 + 105, 320 + 210 },
- { 240 - 100, 320 - 200, 240 + 100, 320 + 200 },
- { 240 - 95, 320 - 190, 240 + 95, 320 + 190 },
- { 240 - 90, 320 - 180, 240 + 90, 320 + 180 },
- { 240 - 85, 320 - 170, 240 + 85, 320 + 170 },
- { 240 - 80, 320 - 160, 240 + 80, 320 + 160 },
- { 240 - 75, 320 - 150, 240 + 75, 320 + 150 },
- { 240 - 70, 320 - 140, 240 + 70, 320 + 140 },
- { 240 - 65, 320 - 130, 240 + 65, 320 + 130 },
- { 240 - 60, 320 - 120, 240 + 60, 320 + 120 },
- { 240 - 55, 320 - 110, 240 + 55, 320 + 110 },
- { 240 - 50, 320 - 100, 240 + 50, 320 + 100 },
- { 240 - 45, 320 - 90, 240 + 45, 320 + 90 },
- { 240 - 40, 320 - 80, 240 + 40, 320 + 80 },
- { 240 - 35, 320 - 70, 240 + 35, 320 + 70 },
- { 240 - 30, 320 - 60, 240 + 30, 320 + 60 },
- { 240 - 25, 320 - 50, 240 + 25, 320 + 50 },
- { 240 - 20, 320 - 40, 240 + 20, 320 + 40 } }
- };
-
- MRect largerRect[2][19] = { { { 240 - 11, 320 - 30, 240 + 11, 320 + 30 },
- { 240 - 44, 320 - 120, 240 + 44, 320 + 120 },
- { 240 - 66, 320 - 180, 240 + 66, 320 + 180 },
- { 240 - 77, 320 - 210, 240 + 77, 320 + 210 },
- { 240 - 88, 320 - 230, 240 + 88, 320 + 230 },
- { 240 - 97, 320 - 245, 240 + 97, 320 + 245 },
- { 240 - 104, 320 - 252, 240 + 104, 320 + 252 },
- { 240 - 111, 320 - 255, 240 + 111, 320 + 255 },
- { 240 - 117, 320 - 252, 240 + 117, 320 + 252 },
- { 240 - 121, 320 - 245, 240 + 121, 320 + 245 },
- { 240 - 124, 320 - 238, 240 + 124, 320 + 238 },
- { 240 - 126, 320 - 232, 240 + 126, 320 + 232 },
- { 240 - 128, 320 - 228, 240 + 128, 320 + 228 },
- { 240 - 130, 320 - 232, 240 + 130, 320 + 230 },
- { 240 - 130, 320 - 238, 240 + 130, 320 + 232 },
- { 240 - 131, 320 - 242, 240 + 131, 320 + 242 },
- { 240 - 131, 320 - 244, 240 + 131, 320 + 244 },
- { 240 - 131, 320 - 242, 240 + 131, 320 + 242 },
- { 240 - 132, 320 - 240, 240 + 132, 320 + 240 } },
- { { 240 - 121, 320 - 220, 240 + 121, 320 + 220 },
- { 240 - 115, 320 - 210, 240 + 115, 320 + 210 },
- { 240 - 110, 320 - 200, 240 + 110, 320 + 200 },
- { 240 - 104, 320 - 190, 240 + 104, 320 + 190 },
- { 240 - 99, 320 - 180, 240 + 99, 320 + 180 },
- { 240 - 93, 320 - 170, 240 + 93, 320 + 170 },
- { 240 - 88, 320 - 160, 240 + 88, 320 + 160 },
- { 240 - 82, 320 - 150, 240 + 82, 320 + 150 },
- { 240 - 77, 320 - 140, 240 + 77, 320 + 140 },
- { 240 - 71, 320 - 130, 240 + 71, 320 + 130 },
- { 240 - 66, 320 - 120, 240 + 66, 320 + 120 },
- { 240 - 60, 320 - 110, 240 + 60, 320 + 110 },
- { 240 - 55, 320 - 100, 240 + 55, 320 + 100 },
- { 240 - 49, 320 - 90, 240 + 49, 320 + 90 },
- { 240 - 44, 320 - 80, 240 + 44, 320 + 80 },
- { 240 - 38, 320 - 70, 240 + 38, 320 + 70 },
- { 240 - 33, 320 - 60, 240 + 33, 320 + 60 },
- { 240 - 27, 320 - 50, 240 + 27, 320 + 50 },
- { 240 - 22, 320 - 40, 240 + 22, 320 + 40 } }
- };
-
- int colorInt, shading;
- float colorFrac, nColorFrac;
- MRect newRect;
- SDL_Rect sdlRect;
-
- if( *target > 18 )
- {
- *target = 18;
- animationStageComplete = true;
- }
-
- colorInt = (int) floor( *colorWrap );
- colorFrac = *colorWrap - colorInt;
-
- newRect = larger? largerRect[animationType][*target]: normalRect[animationType][*target];
- shading = ((animationType == 0) ? (*target * 24 / 18): (24 - (*target * 2 / 3)));
-
- {
- float r1 = backColor[colorInt ].red, g1 = backColor[colorInt ].green, b1 = backColor[colorInt ].blue,
- r2 = backColor[(colorInt+1)&3].red, g2 = backColor[(colorInt+1)&3].green, b2 = backColor[(colorInt+1)&3].blue,
- r3 = backColor[(colorInt+2)&3].red, g3 = backColor[(colorInt+2)&3].green, b3 = backColor[(colorInt+2)&3].blue,
- r4 = backColor[(colorInt+3)&3].red, g4 = backColor[(colorInt+3)&3].green, b4 = backColor[(colorInt+3)&3].blue;
-
- nColorFrac = 1 - colorFrac;
-
- SDLU_AcquireSurface( drawSurface );
-
- SurfaceBlitBlendOver( backSurface, drawSurface,
- &newRect, &newRect,
- (int)((r1 * nColorFrac) + (r2 * colorFrac)),
- (int)((g1 * nColorFrac) + (g2 * colorFrac)),
- (int)((b1 * nColorFrac) + (b2 * colorFrac)),
- (int)((r2 * nColorFrac) + (r3 * colorFrac)),
- (int)((g2 * nColorFrac) + (g3 * colorFrac)),
- (int)((b2 * nColorFrac) + (b3 * colorFrac)),
- (int)((r4 * nColorFrac) + (r1 * colorFrac)),
- (int)((g4 * nColorFrac) + (g1 * colorFrac)),
- (int)((b4 * nColorFrac) + (b1 * colorFrac)),
- (int)((r3 * nColorFrac) + (r4 * colorFrac)),
- (int)((g3 * nColorFrac) + (g4 * colorFrac)),
- (int)((b3 * nColorFrac) + (b4 * colorFrac)),
- _5TO8(shading) );
-
- if( pauseRect->left < newRect.left )
- {
- MRect eraseRect = *pauseRect;
- pauseRect->left = eraseRect.right = newRect.left;
-
- SDLU_MRectToSDLRect( &eraseRect, &sdlRect );
- SDLU_BlitSurface( backSurface, &sdlRect,
- drawSurface, &sdlRect );
- }
-
- if( pauseRect->right > newRect.right )
- {
- MRect eraseRect = *pauseRect;
- pauseRect->right = eraseRect.left = newRect.right;
-
- SDLU_MRectToSDLRect( &eraseRect, &sdlRect );
- SDLU_BlitSurface( backSurface, &sdlRect,
- drawSurface, &sdlRect );
- }
-
- if( pauseRect->top < newRect.top )
- {
- MRect eraseRect = *pauseRect;
- pauseRect->top = eraseRect.bottom = newRect.top;
-
- SDLU_MRectToSDLRect( &eraseRect, &sdlRect );
- SDLU_BlitSurface( backSurface, &sdlRect,
- drawSurface, &sdlRect );
- }
-
- if( pauseRect->bottom > newRect.bottom )
- {
- MRect eraseRect = *pauseRect;
- pauseRect->bottom = eraseRect.top = newRect.bottom;
-
- SDLU_MRectToSDLRect( &eraseRect, &sdlRect );
- SDLU_BlitSurface( backSurface, &sdlRect,
- drawSurface, &sdlRect );
- }
-
- SDLU_ReleaseSurface( drawSurface );
- }
-
- *pauseRect = newRect;
-
- *colorWrap += colorInc * skip;
- if( *colorWrap >= 4 ) *colorWrap -= 4;
-
- *target += skip;
-
- return animationStageComplete;
-}
-
-#if USE_CURSOR_SPRITE
-static void DrawDialogCursor( MRect *pauseRect, int *shade )
-{
- MPoint p, q;
- (void) shade;
-
- SDLU_GetMouse( &p );
-
- if( p.h < (pauseRect->left ) ) p.h = pauseRect->left;
- if( p.h > (pauseRect->right - 5) ) p.h = pauseRect->right - 5;
- if( p.v < (pauseRect->top ) ) p.v = pauseRect->top;
- if( p.v > (pauseRect->bottom - 5) ) p.v = pauseRect->bottom - 5;
- q = p;
-
- SDLU_AcquireSurface( drawSurface );
-
- SurfaceBlitCharacter( smallFont, '\x05', &p, 0, 0, 0, 0 );
- SurfaceBlitCharacter( smallFont, '\x04', &q, 255, 255, 255, 0 );
-
- SDLU_ReleaseSurface( drawSurface );
-}
-#endif
-
-static void DrawDialogLogo( MRect *pauseRect, int shade )
-{
- MRect drawRect;
- int alpha;
-
- drawRect.left = (pauseRect->left + ((pauseRect->right - pauseRect->left) * 1 / 2) ) - (logoRect.right / 2);
- drawRect.top = (pauseRect->top + 14);
- drawRect.bottom = drawRect.top + logoRect.bottom;
- drawRect.right = drawRect.left + logoRect.right;
-
- SDLU_AcquireSurface( drawSurface );
-
- alpha = (shade > 63)? 255: (shade * 4);
-
- SurfaceBlitWeightedDualAlpha( drawSurface, logoSurface, logoMaskSurface, logoAlphaSurface, drawSurface,
- &drawRect, &logoRect, &logoRect, &logoRect, &drawRect,
- alpha );
-
- SDLU_ReleaseSurface( drawSurface );
-}
-
-
-enum
-{
- kNothing = -1,
- kBack = -2,
-
-// main pause screen (kEndGame is reused in continue and register)
- kMusic = 0, kResume,
- kSound, kEndGame,
- kVideo, kControls,
- kWarp,
-
-// continue screen
- kContinue,
-
-// controls screen
- k1PLeft, k2PLeft,
- k1PRight, k2PRight,
- k1PDrop, k2PDrop,
- k1PRotate, k2PRotate,
- kControlsOK, kControlsReset,
-
-// video settings screen
- kFullscreen,
- kWidescreen,
- kScalingMode,
- kVideoOK,
-};
-
-static void DrawContinueContents( int *item, int shade )
-{
- char line[4][50] = { "Do you want to continue?",
- "Yes",
- "No",
- "" };
- MPoint dPoint[4] = { {233, 210}, {280, 220}, {280, 400}, {335, 400} }, hPoint = {255, 320};
- static int lastCountdown = 0;
- int index, countdown, fade;
- int r, g, b;
-
- sprintf( line[3], "%d credit%c", credits, (credits != 1)? 's': ' ' );
-
- SDLU_AcquireSurface( drawSurface );
-
- for( index=0; index<4; index++ )
- {
- DrawRainbowText( smallFont, line[index], dPoint[index], (0.25 * index) + (0.075 * shade),
- ( (index == 0) ||
- ((index == 1) && (*item == kContinue)) ||
- ((index == 2) && (*item == kEndGame )) )? kTextBrightRainbow: kTextRainbow );
- }
-
- countdown = shade / 100;
- if( countdown < 10 )
- {
- continueTimeOut = false;
-
- if( (countdown != 0) && (countdown != lastCountdown) )
- {
- PlayMono( kContinueSnd );
- }
- lastCountdown = countdown;
-
- if( countdown < 5 )
- {
- r = (countdown * 31) / 5;
- g = 31;
- }
- else
- {
- r = 31;
- g = ((10 - countdown) * 31) / 5;
- }
-
- fade = shade % 100;
- if( fade > 50 ) fade = 50;
- r = ((31 * (49 - fade)) + (r * fade)) / 49;
- g = ((31 * (49 - fade)) + (g * fade)) / 49;
- b = ((31 * (49 - fade))) / 49;
-
- countdown = '9' - countdown;
- hPoint.h -= continueFont->width[countdown] / 2;
-
- for( shade = 4; shade > 0; shade-- )
- {
- MPoint hP = hPoint;
-
- hP.h += 2 * shade;
- hP.v += 2 * shade;
-
- int weight = 20 - 4*shade;
-
- SurfaceBlitWeightedCharacter( continueFont, countdown, &hP, 0, 0, 0, _5TO8(weight) );
- }
-
- SurfaceBlitCharacter( continueFont, countdown, &hPoint, _5TO8(r), _5TO8(g), _5TO8(b), 0 );
- }
- else
- {
- continueTimeOut = true;
- }
-
- SDLU_ReleaseSurface( drawSurface );
-}
-
-static void DrawHiScoreContents( int *item, int shade )
-{
- MPoint dPoint[3] = { {240, 640}, {260, 640}, {335, 400} }, hPoint = {294, 145};
- MPoint dashedLinePoint = { 320, 140 };
- int index;
- int nameLength;
- const char* line[3];
- const char* scan;
-
- (void) item; // is unused
-
- line[0] = highScoreText;
- line[1] = "Please enter your name and press return:";
- line[2] = highScoreRank;
-
- for( index=0; index<2; index++ )
- {
- scan = line[index];
- while( *scan )
- dPoint[index].h -= smallFont->width[(uint8_t) * scan++];
-
- dPoint[index].h /= 2;
- }
-
- SDLU_AcquireSurface( drawSurface );
-
- while( dashedLinePoint.h < 490 )
- {
- SurfaceBlitCharacter( dashedLineFont, '.', &dashedLinePoint, 0, 0, 0, 0 );
- }
-
- nameLength = int(strlen(highScoreName));
- for( index = 0; index < nameLength; index++ )
- {
- SurfaceBlitCharacter( bigFont, highScoreName[index], &hPoint, 255, 255, 255, 1 );
- if( hPoint.h >= 475 )
- {
- highScoreName[index] = '\0';
- break;
- }
- }
-
- index = (int)(( 1.0 + sin( MTickCount() / 7.5 ) ) * 120.0);
- SurfaceBlitCharacter( bigFont, '|', &hPoint, index, index, 255, 1 );
-
- for( index=0; index<3; index++ )
- {
- DrawRainbowText( smallFont, line[index], dPoint[index], (0.25 * index) + (0.075 * shade), (index != 2)? kTextBrightRainbow: kTextRainbow );
- }
-
- SDLU_ReleaseSurface( drawSurface );
-}
-
-static void DrawControlsContents( int *item, int shade )
-{
- MBoolean highlight;
- MPoint dPoint;
- int index;
- const char* controlName;
- int r, g, b;
- const char label[8][20] = { "1P Left", "2P Left",
- "1P Right", "2P Right",
- "1P Drop", "2P Drop",
- "1P Rotate", "2P Rotate" };
-
-
- SDLU_AcquireSurface( drawSurface );
-
- for( index=0; index<8; index++ )
- {
- highlight = (index == (*item - k1PLeft));
-
- dPoint.v = 229 + ((index & ~1) * 13);
- dPoint.h = (index & 1)? 325: 130;
- DrawRainbowText( smallFont, label[index], dPoint, (0.25 * index) + (0.075 * shade), highlight? kTextBrightRainbow: kTextRainbow );
-
- dPoint.v = 245 + ((index & ~1) * 13);
- dPoint.h = (index & 1)? 420: 225;
-
- r = highlight? 255: 0;
- g = b = (int)(highlight? 255.0 - (88.0 * (sin(shade * 0.2) + 1.0)): 0.0);
-
- SurfaceBlitCharacter( dashedLineFont, '.', &dPoint, r, g, b, 0 );
- SurfaceBlitCharacter( dashedLineFont, '.', &dPoint, r, g, b, 0 );
- SurfaceBlitCharacter( dashedLineFont, '.', &dPoint, r, g, b, 0 );
- SurfaceBlitCharacter( dashedLineFont, '.', &dPoint, r, g, b, 0 );
- SurfaceBlitCharacter( dashedLineFont, '.', &dPoint, r, g, b, 0 ); // 80 pixels across
-
- controlName = SDL_GetKeyName( playerKeys[index & 1][index >> 1] );
- if( controlName == NULL ) controlName = "???";
-
- dPoint.v = 231 + ((index & ~1) * 13);
- dPoint.h = (index & 1)? 460: 265;
- dPoint.h -= GetTextWidth( tinyFont, controlName ) / 2;
- DrawRainbowText( tinyFont, controlName, dPoint, (0.1 * shade), (controlToReplace == index)? kTextBlueGlow: kTextWhite );
- }
-
- dPoint.h = 200;
- dPoint.v = 340;
- DrawRainbowText( smallFont, "\x03 OK", dPoint, 8.0 + (0.075 * shade), (*item == kControlsOK)? kTextBrightRainbow: kTextRainbow );
-
- dPoint.h = 365;
- dPoint.v = 340;
- DrawRainbowText( smallFont, "\x03 Reset", dPoint, 8.25 + (0.075 * shade), (*item == kControlsReset)? kTextBrightRainbow: kTextRainbow );
-
- SDLU_ReleaseSurface( drawSurface );
-}
-
-static void DrawPauseContents( int *item, int shade )
-{
- const char *line[] =
- {
- musicOn ? "\x01 Music" : "\x02 Music",
- level == kTutorialLevel ? "\x03 Skip Tutorial" : "\x03 Resume",
- soundOn ? "\x01 Sound" : "\x02 Sound",
- "\x03 End Game",
- "\x03 Video",
- "\x03 Controls",
- };
-
- SDLU_AcquireSurface( drawSurface );
-
- for( int i = 0; i < arrsize(line); i++ )
- {
- MPoint dPoint;
- dPoint.h = (i & 1)? 340: 180;
- dPoint.v = 240 + ((i & ~1) * 15);
-
- DrawRainbowText( smallFont, line[i], dPoint, (0.25 * i) + (0.075 * shade), (*item == i)? kTextBrightRainbow: kTextRainbow );
- }
-
- SDLU_ReleaseSurface( drawSurface );
-}
-
-static void DrawVideoSettingsContents(int* item, int shade)
-{
- struct ZoneLabel
- {
- int item;
- const char* text;
- }
- labels[] =
- {
- { kFullscreen, fullscreen ? "\x01 Fullscreen" : "\x02 Fullscreen" },
- { kWidescreen, widescreen ? "\x01 Widescreen" : "\x02 Widescreen" },
- { kScalingMode, crispUpscaling ? "\x01 Crisp upscaling" : "\x02 Crisp upscaling" },
- { kVideoOK, "\x03 OK" },
- };
-
- SDLU_AcquireSurface(drawSurface);
-
- for (int i = 0; i < arrsize(labels); i++)
- {
- MPoint dPoint;
- dPoint.h = 180;
- dPoint.v = 240 + (i * 30);
-
- DrawRainbowText(smallFont, labels[i].text, dPoint, (0.25 * i) + (0.075 * shade), (*item == labels[i].item) ? kTextBrightRainbow : kTextRainbow);
- }
-
- SDLU_ReleaseSurface(drawSurface);
-}
-
-static MBoolean GetClickedZone( int* item, SDL_Keycode inSDLKey, int numZones, const ClickableZone* zones )
-{
- if( inSDLKey == SDLK_ESCAPE )
- {
- *item = kBack;
- return true;
- }
-
- MPoint p;
- SDLU_GetMouse(&p);
-
- int trigger = SDLU_Button();
-
- *item = kNothing;
- for( int i = 0; i < numZones; i++ )
- {
- if( MPointInMRect( p, &zones[i].rect ) )
- {
- *item = zones[i].item;
- }
- }
-
- return trigger;
-}
-
-
-static MBoolean ContinueSelected( int *item, unsigned char inKey, SDL_Keycode inSDLKey )
-{
- static const ClickableZone zones[] =
- {
- { kContinue, {280, 220, 300, 260} },
- { kEndGame, {280, 400, 300, 440} },
- };
-
- (void) inSDLKey; // is unused
-
- if( continueTimeOut )
- {
- *item = kEndGame;
- return true;
- }
-
- int trigger = GetClickedZone( item, inSDLKey, arrsize(zones), zones );
-
- if (trigger && *item == kBack)
- *item = kContinue;
-
- return trigger && *item != kNothing;
-}
-
-static MBoolean HiScoreSelected( int *item, unsigned char inKey, SDL_Keycode inSDLKey )
-{
- int nameLength = int(strlen(highScoreName));
-
- // return (SDL key)
- if( inSDLKey == SDLK_RETURN )
- {
- if( nameLength > 0 )
- {
- *item = kResume;
- PlayMono( kSquishy );
- return true;
- }
- else
- {
- PlayMono( kClick );
- }
- }
-
- // backspace (SDL key)
- if( inSDLKey == SDLK_BACKSPACE )
- {
- if( nameLength > 0 )
- {
- highScoreName[ nameLength-1 ] = '\0';
- PlayMono( kClick );
- }
- }
-
- // characters (ASCII key!)
- if( bigFont->width[inKey] != 0 )
- {
- highScoreName[ nameLength++ ] = inKey;
- highScoreName[ nameLength ] = '\0';
- PlayMono( kPlace );
- }
-
- *item = kNothing;
- return false;
-}
-
-
-static MBoolean ControlsSelected( int *item, unsigned char inKey, SDL_Keycode inSDLKey )
-{
- MPoint p;
- MRect dRect;
- int index;
- static MBoolean lastDown = false;
- MBoolean down;
- int returnValue = 0;
-
- static const ClickableZone buttonZones[] =
- {
- { kControlsOK, { 340, 200, 360, 255 } },
- { kControlsReset, { 340, 365, 360, 450 } },
- };
-
- (void) inKey; // unused
-
- *item = kNothing;
-
-
- down = GetClickedZone( item, inSDLKey, arrsize(buttonZones), buttonZones );
-
- if ( down && *item != kNothing )
- {
- if (!lastDown)
- {
- switch (*item)
- {
- case kBack:
- case kControlsOK:
- PlayMono(kClick);
- returnValue = 1;
- controlToReplace = -1;
- break;
-
- case kControlsReset:
- PlayMono(kClick);
- memcpy(playerKeys, defaultPlayerKeys, sizeof(playerKeys));
- break;
- }
- }
- }
- else
- {
- SDLU_GetMouse(&p);
-
- for( index=0; index<8; index++ )
- {
- dRect.top = 229 + ((index & ~1) * 13);
- dRect.left = (index & 1)? 325: 130;
- dRect.bottom = dRect.top + 24;
- dRect.right = dRect.left + 175;
-
- if( MPointInMRect( p, &dRect ) )
- {
- *item = k1PLeft + index;
- if( down && !lastDown && !AnyKeyIsPressed() )
- {
- controlToReplace = (controlToReplace == index)? -1: index;
- }
- break;
- }
- }
- }
-
- if( inSDLKey != 0 && controlToReplace != -1 )
- {
- playerKeys[controlToReplace & 1][controlToReplace >> 1] = inSDLKey;
- controlToReplace = -1;
- }
-
- lastDown = down;
-
- return returnValue;
-}
-
-
-static MBoolean PauseSelected( int *item, unsigned char inKey, SDL_Keycode inSDLKey )
-{
- (void) inSDLKey; // is unused
-
- static const ClickableZone zones[] =
- {
- { kMusic, { 240, 180, 260, 320 } }, { kResume, { 240, 340, 260, 480 } },
- { kSound, { 270, 180, 290, 320 } }, { kEndGame, { 270, 340, 290, 480 } },
- { kVideo, { 300, 180, 320, 320 } }, { kControls, { 300, 340, 320, 480 } },
- { kWarp, { 330, 180, 350, 320 } },
- };
-
- static MBoolean lastDown = false;
-
- int trigger = GetClickedZone( item, inSDLKey, arrsize(zones), zones );
-
- if( trigger )
- {
- if( !lastDown )
- {
- lastDown = true;
-
- switch( *item )
- {
- case kSound:
- PlayMono( kClick );
- soundOn = !soundOn;
- PlayMono( kClick );
- return false;
-
- case kMusic:
- PlayMono( kClick );
- musicOn = !musicOn;
- EnableMusic( musicOn );
- return false;
-
- case kFullscreen:
- fullscreen = !fullscreen;
- SetFullscreen( fullscreen );
- PlayMono( kClick );
- return false;
-
- case kScalingMode:
- crispUpscaling = !crispUpscaling;
- SDLU_CreateRendererTexture();
- PlayMono(kClick);
- return false;
-
- case kEndGame:
- case kResume:
- case kBack:
- case kControls:
- case kVideo:
- PlayMono( kClick );
- return true;
-
- case kWarp:
- if( ControlKeyIsPressed( ) )
- {
- PlayMono(kLevelUp);
- level++; //Warp( );
- return true;
- }
- else
- {
- *item = kNothing;
- }
- return false;
- }
- }
- }
- else
- {
- lastDown = false;
- }
-
- return false;
-}
-
-
-
-static MBoolean VideoSettingsSelected( int *item, unsigned char inKey, SDL_Keycode inSDLKey )
-{
- (void) inSDLKey; // is unused
-
- static const ClickableZone zones[] =
- {
- { kFullscreen, { 240, 180, 260, 320 } },
- { kWidescreen, { 270, 180, 290, 320 } },
- { kScalingMode, { 300, 180, 320, 320 } },
- { kVideoOK, { 330, 180, 350, 320 } },
- };
-
- static MBoolean lastDown = false;
-
- int trigger = GetClickedZone( item, inSDLKey, arrsize(zones), zones );
-
- if( trigger )
- {
- if( !lastDown )
- {
- lastDown = true;
-
- switch( *item )
- {
- case kNothing:
- break;
-
- case kFullscreen:
- fullscreen = !fullscreen;
- SetFullscreen( fullscreen );
- PlayMono( kClick );
- return false;
-
- case kScalingMode:
- crispUpscaling = !crispUpscaling;
- SDLU_CreateRendererTexture();
- PlayMono(kClick);
- return false;
-
- case kWidescreen:
- widescreen= !widescreen;
- ResetWidescreenLayout();
- SDLU_CreateRendererTexture();
- SetFullscreen(fullscreen);
- PlayMono(kClick);
-
- NeedRefresh();
- //RefreshAll();
- //RefreshPlayerWindow(0);
- //RefreshPlayerWindow(1);
-
- return false;
-
- default:
- PlayMono( kClick );
- return true;
- }
- }
- }
- else
- {
- lastDown = false;
- }
-
- return false;
-}
-
-void HandleDialog( int type )
-{
- const float lighten[4] = { 96.0f, 48.0f, 8.0f, 48.0f };
- const MRect boardWorldZRect = {0, 0, kBlobVertSize * (kGridDown-1), kBlobHorizSize * kGridAcross};
- SDL_Rect fullSDLRect = { 0, 0, 640, 480 };
- SDL_Rect joinSDLRect;
- int skip = 1;
- int count;
- char inASCII;
- SDL_Keycode inSDLKey;
- MRect pauseRect, joinRect;
-
- // Clear state
- whichField = nameField;
- nameField[0] = '\0';
- keyField[0] = '\0';
- batsuAlpha = 0;
- controlToReplace = -1;
-
- // Remember dialog info
- dialogType = type;
- dialogStage = kOpening;
- colorWrap = 0;
- colorInc = (RandomBefore(250) + 250.0) / 10000.0;
-
- smallFont = GetFont( picFont );
- tinyFont = GetFont( picTinyFont );
- bigFont = GetFont( picHiScoreFont );
- dashedLineFont = GetFont( picDashedLineFont );
- continueFont = GetFont( picContinueFont );
- batsuFont = GetFont( picBatsuFont );
-
- // Pick some colors to animate.
- for( count=0; count<4; count++ )
- {
- SDL_Color inColor;
-
- SDLU_GetPixel( boardSurface[0], RandomBefore( boardWorldZRect.right ), RandomBefore( boardWorldZRect.bottom ), &inColor );
-
- backColor[count].red = min( 255.0f, inColor.r + lighten[count] );
- backColor[count].green = min( 255.0f, inColor.g + lighten[count] );
- backColor[count].blue = min( 255.0f, inColor.b + lighten[count] );
- }
-
- // Get some graphics that we're going to need
- logoSurface = LoadPICTAsSurface( picLogo, 32 );
- logoAlphaSurface = LoadPICTAsSurface( picLogoAlpha, 32 );
- logoMaskSurface = LoadPICTAsSurface( picLogoMask, MASK_DEPTH );
-
- // Get a copy of the current game window contents
- backSurface = SDLU_InitSurface( &fullSDLRect, 32 );
-
- SDLU_BlitSurface( g_frontSurface, &g_frontSurface->clip_rect,
- backSurface, &backSurface->clip_rect );
-
- drawSurface = SDLU_InitSurface( &fullSDLRect, 32 );
-
- SDLU_BlitSurface( backSurface, &backSurface->clip_rect,
- drawSurface, &drawSurface->clip_rect );
-
- //
-
- PlayMono( kWhomp );
- dialogTimer = MTickCount();
- dialogTarget = 0;
- dialogShade = 0;
- dialogStageComplete = false;
- dialogItem = kNothing;
- lastPauseRect.top = lastPauseRect.left = 9999;
- lastPauseRect.bottom = lastPauseRect.right = -9999;
-
- SDLU_StartWatchingTyping();
-
- DoFullRepaint = ItsTimeToRedraw;
-
- while( ((dialogStage != kClosing) || !dialogStageComplete) && !finished )
- {
- dialogTimer += skip;
-
- UpdateSound();
-
- // Check mouse and keyboard
- SDLU_CheckASCIITyping( &inASCII );
- SDLU_CheckSDLTyping( &inSDLKey );
-
- if( (dialogStage == kOpening) && dialogStageComplete )
- {
- MBoolean (*DialogSelected[kNumDialogs])( int *item, unsigned char inKey, SDL_Keycode inSDLKey ) =
- {
- PauseSelected,
- HiScoreSelected,
- ContinueSelected,
- ControlsSelected,
- VideoSettingsSelected,
- };
-
- if( DialogSelected[dialogType]( &dialogItem, inASCII, inSDLKey ) )
- {
- SDLU_SetSystemCursor( SYSTEM_CURSOR_OFF );
-
- dialogStage = kClosing;
- dialogTarget = 0;
- }
- }
-
- // Do animation ...
- {
- MBoolean dialogIsLarge = dialogType == kControlsDialog;
-
- pauseRect = lastPauseRect;
- dialogStageComplete = DrawDialogBox( dialogIsLarge, dialogStage, &dialogTarget, skip, &colorWrap, colorInc, &pauseRect );
- SurfaceGetEdges( backSurface, &pauseRect );
- }
-
- if( (dialogStage == kOpening) && dialogStageComplete )
- {
- void (*DialogDraw[kNumDialogs])( int *item, int shade ) =
- {
- DrawPauseContents,
- DrawHiScoreContents,
- DrawContinueContents,
- DrawControlsContents,
- DrawVideoSettingsContents,
- };
-
- // Refresh screen if necessary
- if( timeToRedraw )
- {
- SDLU_BlitFrontSurface( backSurface, &fullSDLRect, &fullSDLRect );
-
- timeToRedraw = false;
- }
-
- // ... and fade in the logo
-
- dialogShade += skip;
-
- {
- bool dialogHasCandyCrisisLogo = true;
-
- if( dialogHasCandyCrisisLogo )
- DrawDialogLogo( &pauseRect, dialogShade );
- }
-
- // ... and animation is complete so add content
- DialogDraw[dialogType]( &dialogItem, dialogShade );
-
-#if USE_CURSOR_SPRITE
- // ... and cursor
- DrawDialogCursor( &pauseRect, &dialogShade );
-#endif
- SDLU_SetSystemCursor( dialogItem == kNothing ? SYSTEM_CURSOR_ARROW : SYSTEM_CURSOR_HAND );
- }
-
- SurfaceCurveEdges( drawSurface, &pauseRect );
-
- // Draw new animation on screen
- UnionMRect( &lastPauseRect, &pauseRect, &joinRect );
- SDLU_MRectToSDLRect( &joinRect, &joinSDLRect );
- SDLU_BlitFrontSurface( drawSurface, &joinSDLRect, &joinSDLRect );
- SDLU_Present();
-
- lastPauseRect = pauseRect;
-
- // Wait for next frame
- if( dialogTimer <= MTickCount( ) )
- {
- dialogTimer = MTickCount( );
- skip = 2;
- }
- else
- {
- skip = 1;
- while( dialogTimer > MTickCount( ) )
- {
- SDLU_Yield();
- }
- }
- }
-
- DoFullRepaint = NoPaint;
-
- SDLU_StopWatchingTyping();
-
- // Bring back previous screen
- SDLU_BlitFrontSurface( backSurface, &fullSDLRect, &fullSDLRect );
- SDLU_Present();
-
- // Dispose the GWorlds and fonts we used
- SDL_FreeSurface( backSurface );
- SDL_FreeSurface( drawSurface );
- SDL_FreeSurface( logoSurface );
- SDL_FreeSurface( logoAlphaSurface );
- SDL_FreeSurface( logoMaskSurface );
-
- switch( dialogItem )
- {
- case kVideo:
- HandleDialog( kVideoDialog );
- HandleDialog( kPauseDialog );
- break;
-
- case kControls:
- HandleDialog( kControlsDialog );
- HandleDialog( kPauseDialog );
- break;
-
- case kEndGame:
- ChooseMusic( -1 );
- AddHiscore( score[0] );
- if( players == 1 )
- {
- ShowGameOverScreen( );
- }
- else
- {
- QuickFadeOut(NULL);
- }
-
- showStartMenu = true;
- break;
-
- case kContinue:
- displayedScore[0] = score[0] = roundStartScore[0];
- ShowScore( 0 );
- BeginRound( true );
- break;
-
- case kWarp:
- {
- int newLevel = level;
-
- InitGame( OptionKeyIsPressed()? kAIControl: kPlayerControl, kAIControl ); // this clears "level" ...
- level = newLevel; // so we need to set "level" afterwards
- BeginRound( true );
- break;
- }
- }
-}
--- /dev/null
+++ b/src/players.c
@@ -1,0 +1,1078 @@
+// players.c
+
+#include "SDLU.h"
+
+#include "main.h"
+#include "players.h"
+#include "gworld.h"
+#include "moving.h"
+#include "graphics.h"
+#include "control.h"
+#include "grays.h"
+#include "soundfx.h"
+#include "next.h"
+#include "random.h"
+#include "victory.h"
+#include "tweak.h"
+#include "zap.h"
+#include "level.h"
+#include "opponent.h"
+#include "gameticks.h"
+#include "blitter.h"
+#include "music.h"
+#include "score.h"
+#include "hiscore.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+unsigned int boredTime[2], hintTime[2], fadeCharTime[2], animTime[2], shadowDepth[2], hintGlow, messageTime;
+int emotions[2];
+int glowColors[][3] = { { 0, 0, 0},
+ {_5TO8(13), _5TO8(26), _5TO8(31)},
+ {_5TO8(13), _5TO8(29), _5TO8(13)},
+ {_5TO8(31), _5TO8(18), _5TO8(31)},
+ {_5TO8(31), _5TO8(14), _5TO8(18)},
+ {_5TO8(31), _5TO8(31), _5TO8(15)},
+ {_5TO8(31), _5TO8(21), _5TO8(13)},
+ {_5TO8(30), _5TO8(22), _5TO8(30)},
+ {_5TO8(20), _5TO8(20), _5TO8(20)} };
+
+void HandlePlayers( void )
+{
+ int player;
+
+ for( player = 0; player<=1; player++ )
+ {
+ UpdateScore( player );
+ UpdateNext( player );
+ BlinkGrays( player );
+ GlowBlobs( player );
+ BlinkBored( player );
+ FadeCharred( player );
+
+ switch( role[player] )
+ {
+ case kWaitForRetrieval:
+ if( control[player] == kAutoControl )
+ {
+ AutoControl( player );
+ break;
+ }
+
+ role[player] = kRetrieveBlobs;
+ // fallthrough
+
+ case kRetrieveBlobs:
+ LockGrays( 1-player );
+ RetrieveBlobs( player );
+ break;
+
+ case kFalling:
+ Falling( player );
+ break;
+
+ case kLockdownBlobs:
+ LockdownBlobs( player );
+ break;
+
+ case kJiggleBlobs:
+ JiggleBlobs( player );
+ break;
+
+ case kFastJiggleBlobs:
+ FastJiggleBlobs( player );
+ break;
+
+ case kPlaceBlobs:
+ PlaceBlobs( player );
+ break;
+
+ case kDropBlobs:
+ DropBlobs( player );
+ break;
+
+ case kZapBlobs:
+ ZapBlobs( player );
+ break;
+
+ case kKillBlobs:
+ KillBlobs( player );
+ break;
+
+ case kDropGrays:
+ DropGrays( player );
+ break;
+
+ case kLosing:
+ Lose( player );
+ break;
+
+ case kWinning:
+ Win( player );
+ break;
+
+ case kChooseDifficulty:
+ ChooseDifficulty( player );
+ break;
+
+ case kWaitingToStart:
+ if( role[1-player] == kWaitingToStart )
+ role[0] = role[1] = kZapBlobs;
+ break;
+
+ case kIdlePlayer:
+ break;
+ }
+
+ UpdatePlayerWindow( player );
+ }
+}
+
+void LockdownBlobs( int player )
+{
+ const int shadowList[] = {
+ kBlobShadowDepth,
+ kBlobShadowDepth*5/6,
+ kBlobShadowDepth*5/6,
+ kBlobShadowDepth*4/6,
+ kBlobShadowDepth*3/6,
+ kBlobShadowDepth*1/6,
+ };
+
+ int frame = (GameTickCount( ) - blobTime[player]) / 2;
+
+ if( frame >= arrsize(shadowList) )
+ {
+ role[player] = kPlaceBlobs;
+ return;
+ }
+
+ shadowDepth[player] = shadowList[frame];
+ UpdateTweak( player, blobJiggleAnimation );
+}
+
+void FastJiggleBlobs( int player )
+{
+ const int shadowList[] = {
+ kBlobShadowDepth,
+ kBlobShadowDepth*5/6,
+ kBlobShadowDepth*5/6,
+ kBlobShadowDepth*4/6,
+ kBlobShadowDepth*3/6,
+ kBlobShadowDepth*2/6,
+ kBlobShadowDepth*1/6,
+ 0
+ };
+
+ int frame = (GameTickCount( ) - blobTime[player]) / 2;
+
+ if( frame >= 8 )
+ {
+ role[player] = kPlaceBlobs;
+ return;
+ }
+
+ switch( control[player] )
+ {
+ case kPlayerControl:
+ PlayerControl( player );
+ break;
+
+ case kAIControl:
+ AIControl( player );
+ break;
+
+ case kAutoControl:
+ AutoControl( player );
+ break;
+ }
+
+ shadowDepth[player] = shadowList[frame];
+ UpdateTweak( player, blobJiggleAnimation );
+
+ if( CanFall( player ) )
+ role[player] = kFalling;
+}
+
+
+void JiggleBlobs( int player )
+{
+ const int shadowList[] = {
+ kBlobShadowDepth, kBlobShadowDepth,
+ kBlobShadowDepth*5/6, kBlobShadowDepth*5/6,
+ kBlobShadowDepth*5/6, kBlobShadowDepth*4/6,
+ kBlobShadowDepth*4/6, kBlobShadowDepth*3/6,
+ kBlobShadowDepth*3/6, kBlobShadowDepth*2/6,
+ kBlobShadowDepth*2/6, kBlobShadowDepth*1/6,
+ kBlobShadowDepth*1/6, 0
+ };
+
+ int frame = (GameTickCount( ) - blobTime[player]) / 2;
+
+ if( frame >= 14 )
+ {
+ role[player] = kPlaceBlobs;
+ return;
+ }
+
+ switch( control[player] )
+ {
+ case kPlayerControl:
+ PlayerControl( player );
+ break;
+
+ case kAIControl:
+ AIControl( player );
+ break;
+
+ case kAutoControl:
+ AutoControl( player );
+ break;
+ }
+
+ shadowDepth[player] = shadowList[frame];
+ UpdateTweak( player, kJiggleAnimation );
+
+ if( CanFall( player ) )
+ role[player] = kFalling;
+}
+
+void PlaceGrenade( int player )
+{
+ MRect myRect;
+ int x, y, atX, atY, color, delay = -6;
+ int currentX = blobX[player], currentY = blobY[player];
+ int charTypes[3][5] = { { kDarkChar | kChar11, kDarkChar | kChar12, kDarkChar | kChar13, kDarkChar | kChar14, kNoCharring },
+ { kNoCharring, kNoCharring, kNoCharring, kNoCharring, kDarkChar | kChar24 },
+ { kDarkChar | kChar31, kDarkChar | kChar32, kDarkChar | kChar33, kDarkChar | kChar34, kNoCharring } };
+
+ int amount = ((level <= kLevels)? level: 1) * 100;
+ int multiplier = 0;
+
+ grenadeFrame[player] = 0;
+ grenadeRect [player].top = (currentY * kBlobVertSize ) - (kBlastHeight/2);
+ grenadeRect [player].left = (currentX * kBlobHorizSize) + (kBlobHorizSize/2) - (kBlastWidth/2);
+ grenadeRect [player].bottom = grenadeRect[player].top + kBlastHeight;
+ grenadeRect [player].right = grenadeRect[player].left + kBlastWidth ;
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ for( x=-1; x<=1; x++ )
+ {
+ atX = currentX + x;
+
+ for( y=-2; y<=2; y++ )
+ {
+ atY = currentY + y;
+
+ if( atX >= 0 && atX < kGridAcross &&
+ atY >= 0 && atY < kGridDown )
+ {
+ if( charTypes[x+1][y+2] != kNoCharring &&
+ grid[player][atX][atY] >= kFirstBlob &&
+ grid[player][atX][atY] <= kLastBlob )
+ {
+ charred[player][atX][atY] = charTypes[x+1][y+2];
+
+ CalcBlobRect( atX, atY, &myRect );
+ SurfaceDrawBlob( player, &myRect, grid[player][atX][atY], suction[player][atX][atY], charred[player][atX][atY] );
+ CleanSpriteArea( player, &myRect );
+ }
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+
+ if( currentY < (kGridDown-1) &&
+ ( grid[player][currentX][currentY+1] >= kFirstBlob &&
+ grid[player][currentX][currentY+1] <= kLastBlob ) )
+ {
+ color = grid[player][currentX][currentY+1];
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ if( grid[player][x][y] == color )
+ {
+ suction[player][x][y] = kInDeath;
+ death[player][x][y] = -abs( x - currentX + y - currentY );
+ multiplier++;
+
+ if( (x <= (kGridAcross-2)) && (grid[player][x+1][y] == kGray) )
+ {
+ suction[player][x+1][y] = kGrayBlink1;
+ death[player][x+1][y] = delay;
+ }
+
+ if( (x >= 1) && (grid[player][x-1][y] == kGray) )
+ {
+ suction[player][x-1][y] = kGrayBlink1;
+ death[player][x-1][y] = delay;
+ }
+
+ if( (y <= (kGridDown-2)) && (grid[player][x][y+1] == kGray) )
+ {
+ suction[player][x][y+1] = kGrayBlink1;
+ death[player][x][y+1] = delay;
+ }
+
+ if( (y >= 1) && (grid[player][x][y-1] == kGray) )
+ {
+ suction[player][x][y-1] = kGrayBlink1;
+ death[player][x][y-1] = delay;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for( x=currentX-1; x<=currentX+1; x++ )
+ {
+ for( y=currentY-1; y<=currentY+1; y++ )
+ {
+ if( x>=0 && x<kGridAcross && y>=0 && y<kGridDown )
+ {
+ if( grid[player][x][y] == kGray )
+ {
+ suction[player][x][y] = kGrayBlink1;
+ death[player][x][y] = delay;
+ }
+ else if( grid[player][x][y] >= kFirstBlob &&
+ grid[player][x][y] <= kLastBlob )
+ {
+ suction[player][x][y] = kInDeath;
+ death[player][x][y] = -abs( x - currentX + y - currentY );
+ multiplier++;
+ }
+ }
+ }
+ }
+ }
+
+ PlayStereo( player, kSplop );
+
+ if( multiplier > 0 )
+ {
+ score[player] += amount * multiplier;
+ ZapScoreDisplay( player, amount, multiplier, blobX[player], blobY[player], 8 );
+ }
+
+ blobTime[player] = GameTickCount( );
+ role[player] = kKillBlobs;
+}
+
+void PlaceBlobs( int player )
+{
+ MRect myRect;
+ int x, y, height;
+ int currentX = blobX[player], currentY = blobY[player];
+
+ potentialCombo[player].x = currentX;
+ potentialCombo[player].r = blobR[player];
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ if( glow[player][x][y] )
+ {
+ glow[player][x][y] = false;
+ CalcBlobRect( x, y, &myRect );
+ SurfaceDrawBlob( player, &myRect, grid[player][x][y], suction[player][x][y], charred[player][x][y] );
+ CleanSpriteArea( player, &myRect );
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+
+ EraseSpriteBlobs( player );
+
+ CalcBlobRect( currentX, currentY, &myRect );
+ CalcSecondBlobOffset( player, &x, &y );
+
+ if( grenade[player] )
+ {
+ PlaceGrenade( player );
+ return;
+ }
+
+ if( magic[player] )
+ {
+ switch( blobR[player] )
+ {
+ case upRotate:
+ height = GetRowHeight(player, currentX)-1;
+ grid[player][currentX][height] = colorB[player];
+ colorA[player] = BestColor( player, currentX, height+1 );
+ grid[player][currentX][height] = kEmpty;
+ break;
+
+ case downRotate:
+ height = GetRowHeight(player, currentX);
+ grid[player][currentX][height] = colorB[player];
+ colorA[player] = BestColor( player, currentX, height-1 );
+ grid[player][currentX][height] = kEmpty;
+ break;
+
+ case rightRotate:
+ height = GetRowHeight(player, currentX+1);
+ grid[player][currentX+1][height] = colorB[player];
+ colorA[player] = BestColor( player, currentX, GetRowHeight(player, currentX) );
+ grid[player][currentX+1][height] = kEmpty;
+ break;
+
+ case leftRotate:
+ height = GetRowHeight(player, currentX-1);
+ grid[player][currentX-1][height] = colorB[player];
+ colorA[player] = BestColor( player, currentX, GetRowHeight(player, currentX) );
+ grid[player][currentX-1][height] = kEmpty;
+ break;
+ }
+ }
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ if( currentX >= 0 && currentX < kGridAcross &&
+ currentY >= 0 && currentY < kGridDown )
+ {
+ grid[player][currentX][currentY] = colorA[player];
+ suction[player][currentX][currentY] = kNoSuction;
+ charred[player][currentX][currentY] = kNoCharring;
+
+ SurfaceDrawBlob( player, &myRect, colorA[player], kNoSuction, kNoCharring );
+ CleanSpriteArea( player, &myRect );
+ }
+
+ OffsetMRect( &myRect, x * kBlobHorizSize, y * kBlobVertSize );
+ currentX += x;
+ currentY += y;
+
+ if( currentX >= 0 && currentX < kGridAcross &&
+ currentY >= 0 && currentY < kGridDown )
+ {
+ grid[player][currentX][currentY] = colorB[player];
+ suction[player][currentX][currentY] = kNoSuction;
+ charred[player][currentX][currentY] = kNoCharring;
+
+ SurfaceDrawBlob( player, &myRect, colorB[player], kNoSuction, kNoCharring );
+ CleanSpriteArea( player, &myRect );
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+
+ blobTime[player] = GameTickCount( );
+ halfway[player] = false;
+ role[player] = kDropBlobs;
+}
+
+void DropBlobs( int player )
+{
+ MBoolean busy = false;
+ signed char tempG[kGridDown], tempC[kGridDown];
+ const int jiggleList[] = { kNoSuction, kSquish,
+ kNoSuction, kSquash,
+ kNoSuction, kSquish,
+ kNoSuction, kSquash };
+ MRect myRect;
+ int x, y;
+
+ if( GameTickCount( ) < blobTime[player] )
+ return;
+
+ blobTime[player] += 1;
+
+ halfway[player] = !halfway[player];
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ if( halfway[player] )
+ {
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y = 0; y<kGridDown; y++ )
+ {
+ tempG[y] = grid[player][x][y];
+ tempC[y] = charred[player][x][y];
+ }
+
+ for( y = kGridDown-1; y; y-- )
+ {
+ if( tempG[y] == kEmpty && tempG[y-1] != kEmpty )
+ {
+ CalcBlobRect( x, y, &myRect );
+ OffsetMRect( &myRect, 0, -kBlobVertSize/2 );
+
+ if( tempG[y-1] == kGray )
+ {
+ SurfaceDrawBoard( player, &myRect );
+ SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
+ }
+ else
+ {
+ SurfaceDrawBlob( player, &myRect, tempG[y-1], kNoSuction, tempC[y-1] );
+ }
+
+ tempG[y] = tempG[y-1];
+ tempG[y-1] = kEmpty;
+ tempC[y] = tempC[y-1];
+ tempC[y-1] = kNoCharring;
+
+ CleanSpriteArea( player, &myRect );
+
+ OffsetMRect( &myRect, 0, -kBlobVertSize );
+ SurfaceDrawBoard( player, &myRect );
+ CleanSpriteArea( player, &myRect );
+ }
+ }
+ }
+ }
+ else
+ {
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y = kGridDown-1; y; y-- )
+ {
+ if( suction[player][x][y] >= kJiggle1 &&
+ suction[player][x][y] < kInDoubt )
+ {
+ CalcBlobRect( x, y, &myRect );
+ SurfaceDrawBlob( player, &myRect, grid[player][x][y],
+ jiggleList[ suction[player][x][y] - kJiggle1 ],
+ charred[player][x][y] );
+ CleanSpriteArea( player, &myRect );
+
+ suction[player][x][y]++;
+
+ busy = true;
+ }
+ else if( grid[player][x][y] == kEmpty && grid[player][x][y-1] != kEmpty )
+ {
+ grid[player][x][y] = grid[player][x][y-1];
+ grid[player][x][y-1] = kEmpty;
+ charred[player][x][y] = charred[player][x][y-1];
+ charred[player][x][y-1] = kNoCharring;
+ suction[player][x][y-1] = kNoSuction;
+
+ CalcBlobRect( x, y, &myRect );
+ if( grid[player][x][y] == kGray )
+ {
+ SurfaceDrawBoard( player, &myRect );
+ SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
+ }
+ else
+ {
+ SurfaceDrawBlob( player, &myRect, grid[player][x][y], kNoSuction, charred[player][x][y] );
+ }
+
+ CleanSpriteArea( player, &myRect );
+
+ OffsetMRect( &myRect, 0, -kBlobVertSize );
+ SurfaceDrawBoard( player, &myRect );
+ CleanSpriteArea( player, &myRect );
+
+ if( grid[player][x][y] >= kFirstBlob && grid[player][x][y] <= kLastBlob )
+ {
+ if( y >= (kGridDown-1) || grid[player][x][y+1] != kEmpty )
+ {
+ suction[player][x][y] = kJiggle1;
+ }
+ }
+ else
+ {
+ suction[player][x][y] = kNoSuction;
+ }
+
+ busy = true;
+ }
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+
+ if( !busy && !halfway[player] )
+ {
+ ResolveSuction( player );
+ role[player] = kZapBlobs;
+ }
+}
+
+void RedrawBoardContents( int player )
+{
+ int x, y;
+ MRect myRect;
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ for( y=0; y<kGridDown; y++ )
+ {
+ for( x=0; x<kGridAcross; x++ )
+ {
+ CalcBlobRect( x, y, &myRect );
+ if( grid[player][x][y] == kGray )
+ {
+ SurfaceDrawBoard( player, &myRect );
+ SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
+ }
+ else
+ {
+ SurfaceDrawBlob( player, &myRect, grid[player][x][y], suction[player][x][y], charred[player][x][y] );
+ }
+
+ CleanSpriteArea( player, &myRect );
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+}
+
+void ResolveSuction( int player )
+{
+ int x, y, suck, actualSuck, color;
+ MRect myRect;
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=1; y<kGridDown; y++ )
+ {
+ suck = kNoSuction;
+ color = grid[player][x][y];
+
+ if( color >= kFirstBlob && color <= kLastBlob )
+ {
+ if( x > 0 )
+ if( grid[player][x-1][y] == color ) suck |= kLeft;
+
+ if( x < (kGridAcross-1) )
+ if( grid[player][x+1][y] == color ) suck |= kRight;
+
+ if( y > 1 )
+ if( grid[player][x][y-1] == color ) suck |= kUp;
+
+ if( y < (kGridDown-1) )
+ if( grid[player][x][y+1] == color ) suck |= kDown;
+
+ actualSuck = suction[player][x][y];
+ if( actualSuck == kBlinkBlob || actualSuck == kSobBlob ) actualSuck = kNoSuction;
+
+ if( actualSuck != suck )
+ {
+ suction[player][x][y] = suck;
+
+ CalcBlobRect( x, y, &myRect );
+ SurfaceDrawBlob( player, &myRect, grid[player][x][y], suck, charred[player][x][y] );
+ CleanSpriteArea( player, &myRect );
+ }
+ }
+ else
+ {
+ suction[player][x][y] = kNoSuction;
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+}
+
+void HandleMagic( int player )
+{
+ if( magic[player] )
+ {
+ colorA[player]++;
+ if( colorA[player] > kBlobTypes ) colorA[player] = 1;
+ }
+}
+
+void Falling( int player )
+{
+ if( role[1-player] == kLosing )
+ {
+ BeginVictory( player );
+ return;
+ }
+
+ shadowDepth[player] = kBlobShadowDepth;
+
+ UpdateTweak( player, kNoSuction );
+
+ if( GameTickCount( ) >= blobTime[player] )
+ {
+ if( CanFall( player ) )
+ {
+ blobTime[player] += dropping[player]? kDropSpeed: speed[player];
+ DoFall( player );
+ }
+ else
+ {
+ blobTime[player] = animTime[player] = GameTickCount( );
+ role[player] = dropping[player]? kFastJiggleBlobs: kJiggleBlobs;
+ anim[player] = 0;
+ PlayStereoFrequency( player, kPlace, player );
+ return;
+ }
+ }
+
+ switch( control[player] )
+ {
+ case kPlayerControl:
+ PlayerControl( player );
+ break;
+
+ case kAIControl:
+ AIControl( player );
+ break;
+
+ case kAutoControl:
+ AutoControl( player );
+ break;
+ }
+}
+
+void RetrieveBlobs( int player )
+{
+ if( (role[1-player] != kLosing) && (grid[player][2][1] != kEmpty) )
+ {
+ EndRound( player );
+ return;
+ }
+
+ // See if it's time to update levels in Solitaire mode
+ if( control[1] == kNobodyControl )
+ {
+ int levelClear[] = { 0,
+ 2500,
+ 7000,
+ 14000,
+ 35000,
+ 50000,
+ 70000,
+ 90000,
+ 120000,
+ 160000,
+ 200000,
+ 500000,
+ 1000000 };
+
+ if( (level <= kLevels) && (score[player] > levelClear[level]) )
+ {
+ FreezeGameTickCount( );
+
+ PlayMono( kLevelUp );
+
+ level++;
+ if( InitCharacter( 1, level ) )
+ {
+ InitCharacter( 1, level );
+ character[0] = character[1];
+ character[0].zapStyle = 0;
+ }
+ else
+ {
+ UnfreezeGameTickCount( );
+ TotalVictory( );
+ return;
+ }
+
+ if( level == 2 || level == 4 || level == 7 || level == 9 ) AddExtraPiece( );
+
+ PrepareStageGraphics( character[1].picture );
+ ChooseMusic( character[1].music );
+
+ UnfreezeGameTickCount( );
+ }
+ }
+
+ PullNext( player );
+
+ dropping[player] = false;
+ anim[player] = 0;
+ magic[player] = nextM[player];
+ grenade[player] = nextG[player];
+ zapIteration[player] = 0;
+ chain[player] = 1;
+
+ emotions[player] = DetermineEmotion(player);
+ if( players == 1 && player == 0 )
+ {
+ if( emotions[0] == kEmotionPanic ) FastMusic(); else SlowMusic();
+ }
+
+ if( magic[player] || grenade[player] )
+ {
+ PlayStereoFrequency( player, kMagic, player );
+ }
+
+ colorA[player] = nextA[player];
+ colorB[player] = nextB[player];
+
+ nextG[player] = GetGrenade( player );
+
+ if( nextG[player] )
+ {
+ nextA[player] = kBombBottom;
+ nextB[player] = kBombTop;
+ nextM[player] = false;
+ }
+ else
+ {
+ nextA[player] = GetPiece( player );
+ nextB[player] = GetPiece( player );
+ nextM[player] = GetMagic( player );
+ }
+
+ ChooseGlowingBlobs( player );
+
+ if( control[player] == kPlayerControl )
+ {
+ memcpy( potentialCombo[player].grid, grid[player], kGridAcross * kGridDown );
+ potentialCombo[player].a = colorA[player];
+ potentialCombo[player].b = colorB[player];
+ potentialCombo[player].m = magic[player];
+ potentialCombo[player].g = grenade[player];
+ potentialCombo[player].lv = level;
+ potentialCombo[player].x = 0;
+ potentialCombo[player].r = 0;
+ potentialCombo[player].player = player;
+ potentialCombo[player].value = 0;
+ potentialCombo[player].name[0] = 0;
+ }
+
+ blobX[player] = 2;
+ blobY[player] = 0;
+ blobR[player] = upRotate;
+ blobSpin[player] = 0;
+ halfway[player] = false;
+
+ DrawSpriteBlobs( player, kNoSuction );
+
+ speed[player] = (signed char)(character[player].dropSpeed);
+ blobTime[player] = animTime[player] = GameTickCount( );
+ role[player] = kFalling;
+
+ if( control[player] == kAIControl )
+ ChooseAIDestination( player );
+}
+
+void ChooseGlowingBlobs( int player )
+{
+ int x, height[kGridAcross];
+
+ if( character[player].hints && !grenade[player] && !magic[player] )
+ {
+ for( x=0; x<kGridAcross; x++ )
+ {
+ height[x] = GetRowHeight( player, x );
+ }
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ if( x>0 && height[x]>1 && height[x-1]>1 )
+ {
+ // left
+
+ grid[player][x ][height[x ]] = colorA[player];
+ grid[player][x-1][height[x-1]] = colorB[player];
+ ConsiderGlow( player, colorA[player], x, height[x ] );
+ ConsiderGlow( player, colorB[player], x, height[x-1] );
+ grid[player][x ][height[x ]] = kEmpty;
+ grid[player][x-1][height[x-1]] = kEmpty;
+ }
+
+ if( x<(kGridAcross-1) && height[x]>1 && height[x+1]>1 )
+ {
+ // right
+
+ grid[player][x ][height[x ]] = colorA[player];
+ grid[player][x+1][height[x+1]] = colorB[player];
+ ConsiderGlow( player, colorA[player], x, height[x ] );
+ ConsiderGlow( player, colorB[player], x, height[x+1] );
+ grid[player][x ][height[x ]] = kEmpty;
+ grid[player][x+1][height[x+1]] = kEmpty;
+ }
+
+ if( height[x]>2 )
+ {
+ // up
+
+ grid[player][x][height[x] ] = colorA[player];
+ grid[player][x][height[x]-1] = colorB[player];
+ ConsiderGlow( player, colorA[player], x, height[x] );
+ ConsiderGlow( player, colorB[player], x, height[x]-1 );
+ grid[player][x][height[x] ] = kEmpty;
+ grid[player][x][height[x]-1] = kEmpty;
+
+ // down
+
+ grid[player][x][height[x] ] = colorB[player];
+ grid[player][x][height[x]-1] = colorA[player];
+ ConsiderGlow( player, colorB[player], x, height[x] );
+ ConsiderGlow( player, colorA[player], x, height[x]-1 );
+ grid[player][x][height[x] ] = kEmpty;
+ grid[player][x][height[x]-1] = kEmpty;
+ }
+ }
+ }
+}
+
+void ConsiderGlow( int player, int color, int x, int y )
+{
+ if( GetChainSize( grid[player], x, y, color ) >= kBlobClusterSize )
+ {
+ CleanWithPolish( grid[player], glow[player], x, y, color );
+ }
+ else
+ {
+ CleanSize( grid[player], x, y, color );
+ }
+}
+
+void GlowBlobs( int player )
+{
+ int x, y, color, suck;
+ MRect myRect;
+
+ if( (!character[player].hints) || (GameTickCount() < hintTime[player]) )
+ return;
+
+ hintTime[player] += 3;
+ if( ++hintGlow >= kGlowArraySize ) hintGlow = 0;
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ if( rowBounce[player][x] == -1 )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ if( glow[player][x][y] && grid[player][x][y] != kEmpty )
+ {
+ CalcBlobRect( x, y, &myRect );
+
+ color = grid[player][x][y];
+ suck = suction[player][x][y];
+
+ SurfaceDrawBlob( player, &myRect, color, suck, charred[player][x][y] );
+ SurfaceDrawColor( &myRect, color, suck, glowColors[color][0], glowColors[color][1], glowColors[color][2], glowArray[hintGlow] );
+ CleanSpriteArea( player, &myRect );
+ }
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+}
+
+void FadeCharred( int player )
+{
+ int x, y;
+ MRect myRect;
+
+ if( GameTickCount() < fadeCharTime[player] || role[player] != kFalling ) return;
+
+ fadeCharTime[player] += 135;
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ if( charred[player][x][y] & 0xF0 )
+ {
+ charred[player][x][y] = ( charred[player][x][y] & 0x0F ) | ( ( charred[player][x][y] & 0xF0 ) - 0x10 );
+
+ if( rowBounce[player][x] == -1 )
+ {
+ CalcBlobRect( x, y, &myRect );
+ SurfaceDrawBlob( player, &myRect, grid[player][x][y], suction[player][x][y], charred[player][x][y] );
+ CleanSpriteArea( player, &myRect );
+ }
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+}
+
+void BlinkBored( int player )
+{
+ MRect myRect;
+ int which, x, y, count;
+
+ if( GameTickCount() < boredTime[player] )
+ return;
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ // undo any previously bored blobs
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ if( ( rowBounce[player][x] == -1 ) &&
+ ( suction[player][x][y] == kBlinkBlob || suction[player][x][y] == kSobBlob ) )
+ {
+ suction[player][x][y] = kNoSuction;
+
+ CalcBlobRect( x, y, &myRect );
+ SurfaceDrawBlob( player, &myRect, grid[player][x][y],
+ suction[player][x][y],
+ charred[player][x][y] );
+ CleanSpriteArea( player, &myRect );
+ }
+ }
+ }
+
+ // make some boredom
+
+ which = RandomBefore( 2 );
+ boredTime[player] += which? 15: 80;
+ which = which? kBlinkBlob: kSobBlob;
+
+ for( count=0; count<5; count++ )
+ {
+ x = RandomBefore( kGridAcross );
+ y = RandomBefore( kGridDown );
+
+ if( rowBounce[player][x] == -1 &&
+ suction[player][x][y] == kNoSuction &&
+ grid[player][x][y] >= kFirstBlob &&
+ grid[player][x][y] <= kLastBlob
+ )
+ {
+ suction[player][x][y] = which;
+
+ CalcBlobRect( x, y, &myRect );
+ SurfaceDrawBlob( player, &myRect,
+ grid[player][x][y],
+ suction[player][x][y],
+ charred[player][x][y] );
+ CleanSpriteArea( player, &myRect );
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+}
+
+void InitPlayers( void )
+{
+ const double windowLoc[ ] = { kLeftPlayerWindowCenter, kRightPlayerWindowCenter };
+
+ playerWindowZRect.top = playerWindowZRect.left = 0;
+ playerWindowZRect.bottom = 288; playerWindowZRect.right = 144;
+
+ playerWindowRect[0] = playerWindowRect[1] = playerWindowZRect;
+ CenterRectOnScreen( &playerWindowRect[0], windowLoc[0], 0.5 );
+ CenterRectOnScreen( &playerWindowRect[1], windowLoc[1], 0.5 );
+}
--- a/src/players.cpp
+++ /dev/null
@@ -1,1078 +1,0 @@
-// players.c
-
-#include "SDLU.h"
-
-#include "main.h"
-#include "players.h"
-#include "gworld.h"
-#include "moving.h"
-#include "graphics.h"
-#include "control.h"
-#include "grays.h"
-#include "soundfx.h"
-#include "next.h"
-#include "random.h"
-#include "victory.h"
-#include "tweak.h"
-#include "zap.h"
-#include "level.h"
-#include "opponent.h"
-#include "gameticks.h"
-#include "blitter.h"
-#include "music.h"
-#include "score.h"
-#include "hiscore.h"
-
-#include <string.h>
-#include <stdlib.h>
-
-unsigned int boredTime[2], hintTime[2], fadeCharTime[2], animTime[2], shadowDepth[2], hintGlow, messageTime;
-int emotions[2];
-int glowColors[][3] = { { 0, 0, 0},
- {_5TO8(13), _5TO8(26), _5TO8(31)},
- {_5TO8(13), _5TO8(29), _5TO8(13)},
- {_5TO8(31), _5TO8(18), _5TO8(31)},
- {_5TO8(31), _5TO8(14), _5TO8(18)},
- {_5TO8(31), _5TO8(31), _5TO8(15)},
- {_5TO8(31), _5TO8(21), _5TO8(13)},
- {_5TO8(30), _5TO8(22), _5TO8(30)},
- {_5TO8(20), _5TO8(20), _5TO8(20)} };
-
-void HandlePlayers( void )
-{
- int player;
-
- for( player = 0; player<=1; player++ )
- {
- UpdateScore( player );
- UpdateNext( player );
- BlinkGrays( player );
- GlowBlobs( player );
- BlinkBored( player );
- FadeCharred( player );
-
- switch( role[player] )
- {
- case kWaitForRetrieval:
- if( control[player] == kAutoControl )
- {
- AutoControl( player );
- break;
- }
-
- role[player] = kRetrieveBlobs;
- // fallthrough
-
- case kRetrieveBlobs:
- LockGrays( 1-player );
- RetrieveBlobs( player );
- break;
-
- case kFalling:
- Falling( player );
- break;
-
- case kLockdownBlobs:
- LockdownBlobs( player );
- break;
-
- case kJiggleBlobs:
- JiggleBlobs( player );
- break;
-
- case kFastJiggleBlobs:
- FastJiggleBlobs( player );
- break;
-
- case kPlaceBlobs:
- PlaceBlobs( player );
- break;
-
- case kDropBlobs:
- DropBlobs( player );
- break;
-
- case kZapBlobs:
- ZapBlobs( player );
- break;
-
- case kKillBlobs:
- KillBlobs( player );
- break;
-
- case kDropGrays:
- DropGrays( player );
- break;
-
- case kLosing:
- Lose( player );
- break;
-
- case kWinning:
- Win( player );
- break;
-
- case kChooseDifficulty:
- ChooseDifficulty( player );
- break;
-
- case kWaitingToStart:
- if( role[1-player] == kWaitingToStart )
- role[0] = role[1] = kZapBlobs;
- break;
-
- case kIdlePlayer:
- break;
- }
-
- UpdatePlayerWindow( player );
- }
-}
-
-void LockdownBlobs( int player )
-{
- const int shadowList[] = {
- kBlobShadowDepth,
- kBlobShadowDepth*5/6,
- kBlobShadowDepth*5/6,
- kBlobShadowDepth*4/6,
- kBlobShadowDepth*3/6,
- kBlobShadowDepth*1/6,
- };
-
- int frame = (GameTickCount( ) - blobTime[player]) / 2;
-
- if( frame >= arrsize(shadowList) )
- {
- role[player] = kPlaceBlobs;
- return;
- }
-
- shadowDepth[player] = shadowList[frame];
- UpdateTweak( player, blobJiggleAnimation );
-}
-
-void FastJiggleBlobs( int player )
-{
- const int shadowList[] = {
- kBlobShadowDepth,
- kBlobShadowDepth*5/6,
- kBlobShadowDepth*5/6,
- kBlobShadowDepth*4/6,
- kBlobShadowDepth*3/6,
- kBlobShadowDepth*2/6,
- kBlobShadowDepth*1/6,
- 0
- };
-
- int frame = (GameTickCount( ) - blobTime[player]) / 2;
-
- if( frame >= 8 )
- {
- role[player] = kPlaceBlobs;
- return;
- }
-
- switch( control[player] )
- {
- case kPlayerControl:
- PlayerControl( player );
- break;
-
- case kAIControl:
- AIControl( player );
- break;
-
- case kAutoControl:
- AutoControl( player );
- break;
- }
-
- shadowDepth[player] = shadowList[frame];
- UpdateTweak( player, blobJiggleAnimation );
-
- if( CanFall( player ) )
- role[player] = kFalling;
-}
-
-
-void JiggleBlobs( int player )
-{
- const int shadowList[] = {
- kBlobShadowDepth, kBlobShadowDepth,
- kBlobShadowDepth*5/6, kBlobShadowDepth*5/6,
- kBlobShadowDepth*5/6, kBlobShadowDepth*4/6,
- kBlobShadowDepth*4/6, kBlobShadowDepth*3/6,
- kBlobShadowDepth*3/6, kBlobShadowDepth*2/6,
- kBlobShadowDepth*2/6, kBlobShadowDepth*1/6,
- kBlobShadowDepth*1/6, 0
- };
-
- int frame = (GameTickCount( ) - blobTime[player]) / 2;
-
- if( frame >= 14 )
- {
- role[player] = kPlaceBlobs;
- return;
- }
-
- switch( control[player] )
- {
- case kPlayerControl:
- PlayerControl( player );
- break;
-
- case kAIControl:
- AIControl( player );
- break;
-
- case kAutoControl:
- AutoControl( player );
- break;
- }
-
- shadowDepth[player] = shadowList[frame];
- UpdateTweak( player, kJiggleAnimation );
-
- if( CanFall( player ) )
- role[player] = kFalling;
-}
-
-void PlaceGrenade( int player )
-{
- MRect myRect;
- int x, y, atX, atY, color, delay = -6;
- int currentX = blobX[player], currentY = blobY[player];
- int charTypes[3][5] = { { kDarkChar | kChar11, kDarkChar | kChar12, kDarkChar | kChar13, kDarkChar | kChar14, kNoCharring },
- { kNoCharring, kNoCharring, kNoCharring, kNoCharring, kDarkChar | kChar24 },
- { kDarkChar | kChar31, kDarkChar | kChar32, kDarkChar | kChar33, kDarkChar | kChar34, kNoCharring } };
-
- int amount = ((level <= kLevels)? level: 1) * 100;
- int multiplier = 0;
-
- grenadeFrame[player] = 0;
- grenadeRect [player].top = (currentY * kBlobVertSize ) - (kBlastHeight/2);
- grenadeRect [player].left = (currentX * kBlobHorizSize) + (kBlobHorizSize/2) - (kBlastWidth/2);
- grenadeRect [player].bottom = grenadeRect[player].top + kBlastHeight;
- grenadeRect [player].right = grenadeRect[player].left + kBlastWidth ;
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- for( x=-1; x<=1; x++ )
- {
- atX = currentX + x;
-
- for( y=-2; y<=2; y++ )
- {
- atY = currentY + y;
-
- if( atX >= 0 && atX < kGridAcross &&
- atY >= 0 && atY < kGridDown )
- {
- if( charTypes[x+1][y+2] != kNoCharring &&
- grid[player][atX][atY] >= kFirstBlob &&
- grid[player][atX][atY] <= kLastBlob )
- {
- charred[player][atX][atY] = charTypes[x+1][y+2];
-
- CalcBlobRect( atX, atY, &myRect );
- SurfaceDrawBlob( player, &myRect, grid[player][atX][atY], suction[player][atX][atY], charred[player][atX][atY] );
- CleanSpriteArea( player, &myRect );
- }
- }
- }
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-
- if( currentY < (kGridDown-1) &&
- ( grid[player][currentX][currentY+1] >= kFirstBlob &&
- grid[player][currentX][currentY+1] <= kLastBlob ) )
- {
- color = grid[player][currentX][currentY+1];
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- if( grid[player][x][y] == color )
- {
- suction[player][x][y] = kInDeath;
- death[player][x][y] = -abs( x - currentX + y - currentY );
- multiplier++;
-
- if( (x <= (kGridAcross-2)) && (grid[player][x+1][y] == kGray) )
- {
- suction[player][x+1][y] = kGrayBlink1;
- death[player][x+1][y] = delay;
- }
-
- if( (x >= 1) && (grid[player][x-1][y] == kGray) )
- {
- suction[player][x-1][y] = kGrayBlink1;
- death[player][x-1][y] = delay;
- }
-
- if( (y <= (kGridDown-2)) && (grid[player][x][y+1] == kGray) )
- {
- suction[player][x][y+1] = kGrayBlink1;
- death[player][x][y+1] = delay;
- }
-
- if( (y >= 1) && (grid[player][x][y-1] == kGray) )
- {
- suction[player][x][y-1] = kGrayBlink1;
- death[player][x][y-1] = delay;
- }
- }
- }
- }
- }
- else
- {
- for( x=currentX-1; x<=currentX+1; x++ )
- {
- for( y=currentY-1; y<=currentY+1; y++ )
- {
- if( x>=0 && x<kGridAcross && y>=0 && y<kGridDown )
- {
- if( grid[player][x][y] == kGray )
- {
- suction[player][x][y] = kGrayBlink1;
- death[player][x][y] = delay;
- }
- else if( grid[player][x][y] >= kFirstBlob &&
- grid[player][x][y] <= kLastBlob )
- {
- suction[player][x][y] = kInDeath;
- death[player][x][y] = -abs( x - currentX + y - currentY );
- multiplier++;
- }
- }
- }
- }
- }
-
- PlayStereo( player, kSplop );
-
- if( multiplier > 0 )
- {
- score[player] += amount * multiplier;
- ZapScoreDisplay( player, amount, multiplier, blobX[player], blobY[player], 8 );
- }
-
- blobTime[player] = GameTickCount( );
- role[player] = kKillBlobs;
-}
-
-void PlaceBlobs( int player )
-{
- MRect myRect;
- int x, y, height;
- int currentX = blobX[player], currentY = blobY[player];
-
- potentialCombo[player].x = currentX;
- potentialCombo[player].r = blobR[player];
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- if( glow[player][x][y] )
- {
- glow[player][x][y] = false;
- CalcBlobRect( x, y, &myRect );
- SurfaceDrawBlob( player, &myRect, grid[player][x][y], suction[player][x][y], charred[player][x][y] );
- CleanSpriteArea( player, &myRect );
- }
- }
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-
- EraseSpriteBlobs( player );
-
- CalcBlobRect( currentX, currentY, &myRect );
- CalcSecondBlobOffset( player, &x, &y );
-
- if( grenade[player] )
- {
- PlaceGrenade( player );
- return;
- }
-
- if( magic[player] )
- {
- switch( blobR[player] )
- {
- case upRotate:
- height = GetRowHeight(player, currentX)-1;
- grid[player][currentX][height] = colorB[player];
- colorA[player] = BestColor( player, currentX, height+1 );
- grid[player][currentX][height] = kEmpty;
- break;
-
- case downRotate:
- height = GetRowHeight(player, currentX);
- grid[player][currentX][height] = colorB[player];
- colorA[player] = BestColor( player, currentX, height-1 );
- grid[player][currentX][height] = kEmpty;
- break;
-
- case rightRotate:
- height = GetRowHeight(player, currentX+1);
- grid[player][currentX+1][height] = colorB[player];
- colorA[player] = BestColor( player, currentX, GetRowHeight(player, currentX) );
- grid[player][currentX+1][height] = kEmpty;
- break;
-
- case leftRotate:
- height = GetRowHeight(player, currentX-1);
- grid[player][currentX-1][height] = colorB[player];
- colorA[player] = BestColor( player, currentX, GetRowHeight(player, currentX) );
- grid[player][currentX-1][height] = kEmpty;
- break;
- }
- }
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- if( currentX >= 0 && currentX < kGridAcross &&
- currentY >= 0 && currentY < kGridDown )
- {
- grid[player][currentX][currentY] = colorA[player];
- suction[player][currentX][currentY] = kNoSuction;
- charred[player][currentX][currentY] = kNoCharring;
-
- SurfaceDrawBlob( player, &myRect, colorA[player], kNoSuction, kNoCharring );
- CleanSpriteArea( player, &myRect );
- }
-
- OffsetMRect( &myRect, x * kBlobHorizSize, y * kBlobVertSize );
- currentX += x;
- currentY += y;
-
- if( currentX >= 0 && currentX < kGridAcross &&
- currentY >= 0 && currentY < kGridDown )
- {
- grid[player][currentX][currentY] = colorB[player];
- suction[player][currentX][currentY] = kNoSuction;
- charred[player][currentX][currentY] = kNoCharring;
-
- SurfaceDrawBlob( player, &myRect, colorB[player], kNoSuction, kNoCharring );
- CleanSpriteArea( player, &myRect );
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-
- blobTime[player] = GameTickCount( );
- halfway[player] = false;
- role[player] = kDropBlobs;
-}
-
-void DropBlobs( int player )
-{
- MBoolean busy = false;
- signed char tempG[kGridDown], tempC[kGridDown];
- const int jiggleList[] = { kNoSuction, kSquish,
- kNoSuction, kSquash,
- kNoSuction, kSquish,
- kNoSuction, kSquash };
- MRect myRect;
- int x, y;
-
- if( GameTickCount( ) < blobTime[player] )
- return;
-
- blobTime[player] += 1;
-
- halfway[player] = !halfway[player];
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- if( halfway[player] )
- {
- for( x=0; x<kGridAcross; x++ )
- {
- for( y = 0; y<kGridDown; y++ )
- {
- tempG[y] = grid[player][x][y];
- tempC[y] = charred[player][x][y];
- }
-
- for( y = kGridDown-1; y; y-- )
- {
- if( tempG[y] == kEmpty && tempG[y-1] != kEmpty )
- {
- CalcBlobRect( x, y, &myRect );
- OffsetMRect( &myRect, 0, -kBlobVertSize/2 );
-
- if( tempG[y-1] == kGray )
- {
- SurfaceDrawBoard( player, &myRect );
- SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
- }
- else
- {
- SurfaceDrawBlob( player, &myRect, tempG[y-1], kNoSuction, tempC[y-1] );
- }
-
- tempG[y] = tempG[y-1];
- tempG[y-1] = kEmpty;
- tempC[y] = tempC[y-1];
- tempC[y-1] = kNoCharring;
-
- CleanSpriteArea( player, &myRect );
-
- OffsetMRect( &myRect, 0, -kBlobVertSize );
- SurfaceDrawBoard( player, &myRect );
- CleanSpriteArea( player, &myRect );
- }
- }
- }
- }
- else
- {
- for( x=0; x<kGridAcross; x++ )
- {
- for( y = kGridDown-1; y; y-- )
- {
- if( suction[player][x][y] >= kJiggle1 &&
- suction[player][x][y] < kInDoubt )
- {
- CalcBlobRect( x, y, &myRect );
- SurfaceDrawBlob( player, &myRect, grid[player][x][y],
- jiggleList[ suction[player][x][y] - kJiggle1 ],
- charred[player][x][y] );
- CleanSpriteArea( player, &myRect );
-
- suction[player][x][y]++;
-
- busy = true;
- }
- else if( grid[player][x][y] == kEmpty && grid[player][x][y-1] != kEmpty )
- {
- grid[player][x][y] = grid[player][x][y-1];
- grid[player][x][y-1] = kEmpty;
- charred[player][x][y] = charred[player][x][y-1];
- charred[player][x][y-1] = kNoCharring;
- suction[player][x][y-1] = kNoSuction;
-
- CalcBlobRect( x, y, &myRect );
- if( grid[player][x][y] == kGray )
- {
- SurfaceDrawBoard( player, &myRect );
- SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
- }
- else
- {
- SurfaceDrawBlob( player, &myRect, grid[player][x][y], kNoSuction, charred[player][x][y] );
- }
-
- CleanSpriteArea( player, &myRect );
-
- OffsetMRect( &myRect, 0, -kBlobVertSize );
- SurfaceDrawBoard( player, &myRect );
- CleanSpriteArea( player, &myRect );
-
- if( grid[player][x][y] >= kFirstBlob && grid[player][x][y] <= kLastBlob )
- {
- if( y >= (kGridDown-1) || grid[player][x][y+1] != kEmpty )
- {
- suction[player][x][y] = kJiggle1;
- }
- }
- else
- {
- suction[player][x][y] = kNoSuction;
- }
-
- busy = true;
- }
- }
- }
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-
- if( !busy && !halfway[player] )
- {
- ResolveSuction( player );
- role[player] = kZapBlobs;
- }
-}
-
-void RedrawBoardContents( int player )
-{
- int x, y;
- MRect myRect;
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- for( y=0; y<kGridDown; y++ )
- {
- for( x=0; x<kGridAcross; x++ )
- {
- CalcBlobRect( x, y, &myRect );
- if( grid[player][x][y] == kGray )
- {
- SurfaceDrawBoard( player, &myRect );
- SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
- }
- else
- {
- SurfaceDrawBlob( player, &myRect, grid[player][x][y], suction[player][x][y], charred[player][x][y] );
- }
-
- CleanSpriteArea( player, &myRect );
- }
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-}
-
-void ResolveSuction( int player )
-{
- int x, y, suck, actualSuck, color;
- MRect myRect;
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=1; y<kGridDown; y++ )
- {
- suck = kNoSuction;
- color = grid[player][x][y];
-
- if( color >= kFirstBlob && color <= kLastBlob )
- {
- if( x > 0 )
- if( grid[player][x-1][y] == color ) suck |= kLeft;
-
- if( x < (kGridAcross-1) )
- if( grid[player][x+1][y] == color ) suck |= kRight;
-
- if( y > 1 )
- if( grid[player][x][y-1] == color ) suck |= kUp;
-
- if( y < (kGridDown-1) )
- if( grid[player][x][y+1] == color ) suck |= kDown;
-
- actualSuck = suction[player][x][y];
- if( actualSuck == kBlinkBlob || actualSuck == kSobBlob ) actualSuck = kNoSuction;
-
- if( actualSuck != suck )
- {
- suction[player][x][y] = suck;
-
- CalcBlobRect( x, y, &myRect );
- SurfaceDrawBlob( player, &myRect, grid[player][x][y], suck, charred[player][x][y] );
- CleanSpriteArea( player, &myRect );
- }
- }
- else
- {
- suction[player][x][y] = kNoSuction;
- }
- }
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-}
-
-void HandleMagic( int player )
-{
- if( magic[player] )
- {
- colorA[player]++;
- if( colorA[player] > kBlobTypes ) colorA[player] = 1;
- }
-}
-
-void Falling( int player )
-{
- if( role[1-player] == kLosing )
- {
- BeginVictory( player );
- return;
- }
-
- shadowDepth[player] = kBlobShadowDepth;
-
- UpdateTweak( player, kNoSuction );
-
- if( GameTickCount( ) >= blobTime[player] )
- {
- if( CanFall( player ) )
- {
- blobTime[player] += dropping[player]? kDropSpeed: speed[player];
- DoFall( player );
- }
- else
- {
- blobTime[player] = animTime[player] = GameTickCount( );
- role[player] = dropping[player]? kFastJiggleBlobs: kJiggleBlobs;
- anim[player] = 0;
- PlayStereoFrequency( player, kPlace, player );
- return;
- }
- }
-
- switch( control[player] )
- {
- case kPlayerControl:
- PlayerControl( player );
- break;
-
- case kAIControl:
- AIControl( player );
- break;
-
- case kAutoControl:
- AutoControl( player );
- break;
- }
-}
-
-void RetrieveBlobs( int player )
-{
- if( (role[1-player] != kLosing) && (grid[player][2][1] != kEmpty) )
- {
- EndRound( player );
- return;
- }
-
- // See if it's time to update levels in Solitaire mode
- if( control[1] == kNobodyControl )
- {
- int levelClear[] = { 0,
- 2500,
- 7000,
- 14000,
- 35000,
- 50000,
- 70000,
- 90000,
- 120000,
- 160000,
- 200000,
- 500000,
- 1000000 };
-
- if( (level <= kLevels) && (score[player] > levelClear[level]) )
- {
- FreezeGameTickCount( );
-
- PlayMono( kLevelUp );
-
- level++;
- if( InitCharacter( 1, level ) )
- {
- InitCharacter( 1, level );
- character[0] = character[1];
- character[0].zapStyle = 0;
- }
- else
- {
- UnfreezeGameTickCount( );
- TotalVictory( );
- return;
- }
-
- if( level == 2 || level == 4 || level == 7 || level == 9 ) AddExtraPiece( );
-
- PrepareStageGraphics( character[1].picture );
- ChooseMusic( character[1].music );
-
- UnfreezeGameTickCount( );
- }
- }
-
- PullNext( player );
-
- dropping[player] = false;
- anim[player] = 0;
- magic[player] = nextM[player];
- grenade[player] = nextG[player];
- zapIteration[player] = 0;
- chain[player] = 1;
-
- emotions[player] = DetermineEmotion(player);
- if( players == 1 && player == 0 )
- {
- if( emotions[0] == kEmotionPanic ) FastMusic(); else SlowMusic();
- }
-
- if( magic[player] || grenade[player] )
- {
- PlayStereoFrequency( player, kMagic, player );
- }
-
- colorA[player] = nextA[player];
- colorB[player] = nextB[player];
-
- nextG[player] = GetGrenade( player );
-
- if( nextG[player] )
- {
- nextA[player] = kBombBottom;
- nextB[player] = kBombTop;
- nextM[player] = false;
- }
- else
- {
- nextA[player] = GetPiece( player );
- nextB[player] = GetPiece( player );
- nextM[player] = GetMagic( player );
- }
-
- ChooseGlowingBlobs( player );
-
- if( control[player] == kPlayerControl )
- {
- memcpy( potentialCombo[player].grid, grid[player], kGridAcross * kGridDown );
- potentialCombo[player].a = colorA[player];
- potentialCombo[player].b = colorB[player];
- potentialCombo[player].m = magic[player];
- potentialCombo[player].g = grenade[player];
- potentialCombo[player].lv = level;
- potentialCombo[player].x = 0;
- potentialCombo[player].r = 0;
- potentialCombo[player].player = player;
- potentialCombo[player].value = 0;
- potentialCombo[player].name[0] = 0;
- }
-
- blobX[player] = 2;
- blobY[player] = 0;
- blobR[player] = upRotate;
- blobSpin[player] = 0;
- halfway[player] = false;
-
- DrawSpriteBlobs( player, kNoSuction );
-
- speed[player] = (signed char)(character[player].dropSpeed);
- blobTime[player] = animTime[player] = GameTickCount( );
- role[player] = kFalling;
-
- if( control[player] == kAIControl )
- ChooseAIDestination( player );
-}
-
-void ChooseGlowingBlobs( int player )
-{
- int x, height[kGridAcross];
-
- if( character[player].hints && !grenade[player] && !magic[player] )
- {
- for( x=0; x<kGridAcross; x++ )
- {
- height[x] = GetRowHeight( player, x );
- }
-
- for( x=0; x<kGridAcross; x++ )
- {
- if( x>0 && height[x]>1 && height[x-1]>1 )
- {
- // left
-
- grid[player][x ][height[x ]] = colorA[player];
- grid[player][x-1][height[x-1]] = colorB[player];
- ConsiderGlow( player, colorA[player], x, height[x ] );
- ConsiderGlow( player, colorB[player], x, height[x-1] );
- grid[player][x ][height[x ]] = kEmpty;
- grid[player][x-1][height[x-1]] = kEmpty;
- }
-
- if( x<(kGridAcross-1) && height[x]>1 && height[x+1]>1 )
- {
- // right
-
- grid[player][x ][height[x ]] = colorA[player];
- grid[player][x+1][height[x+1]] = colorB[player];
- ConsiderGlow( player, colorA[player], x, height[x ] );
- ConsiderGlow( player, colorB[player], x, height[x+1] );
- grid[player][x ][height[x ]] = kEmpty;
- grid[player][x+1][height[x+1]] = kEmpty;
- }
-
- if( height[x]>2 )
- {
- // up
-
- grid[player][x][height[x] ] = colorA[player];
- grid[player][x][height[x]-1] = colorB[player];
- ConsiderGlow( player, colorA[player], x, height[x] );
- ConsiderGlow( player, colorB[player], x, height[x]-1 );
- grid[player][x][height[x] ] = kEmpty;
- grid[player][x][height[x]-1] = kEmpty;
-
- // down
-
- grid[player][x][height[x] ] = colorB[player];
- grid[player][x][height[x]-1] = colorA[player];
- ConsiderGlow( player, colorB[player], x, height[x] );
- ConsiderGlow( player, colorA[player], x, height[x]-1 );
- grid[player][x][height[x] ] = kEmpty;
- grid[player][x][height[x]-1] = kEmpty;
- }
- }
- }
-}
-
-void ConsiderGlow( int player, int color, int x, int y )
-{
- if( GetChainSize( grid[player], x, y, color ) >= kBlobClusterSize )
- {
- CleanWithPolish( grid[player], glow[player], x, y, color );
- }
- else
- {
- CleanSize( grid[player], x, y, color );
- }
-}
-
-void GlowBlobs( int player )
-{
- int x, y, color, suck;
- MRect myRect;
-
- if( (!character[player].hints) || (GameTickCount() < hintTime[player]) )
- return;
-
- hintTime[player] += 3;
- if( ++hintGlow >= kGlowArraySize ) hintGlow = 0;
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- for( x=0; x<kGridAcross; x++ )
- {
- if( rowBounce[player][x] == -1 )
- {
- for( y=0; y<kGridDown; y++ )
- {
- if( glow[player][x][y] && grid[player][x][y] != kEmpty )
- {
- CalcBlobRect( x, y, &myRect );
-
- color = grid[player][x][y];
- suck = suction[player][x][y];
-
- SurfaceDrawBlob( player, &myRect, color, suck, charred[player][x][y] );
- SurfaceDrawColor( &myRect, color, suck, glowColors[color][0], glowColors[color][1], glowColors[color][2], glowArray[hintGlow] );
- CleanSpriteArea( player, &myRect );
- }
- }
- }
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-}
-
-void FadeCharred( int player )
-{
- int x, y;
- MRect myRect;
-
- if( GameTickCount() < fadeCharTime[player] || role[player] != kFalling ) return;
-
- fadeCharTime[player] += 135;
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- if( charred[player][x][y] & 0xF0 )
- {
- charred[player][x][y] = ( charred[player][x][y] & 0x0F ) | ( ( charred[player][x][y] & 0xF0 ) - 0x10 );
-
- if( rowBounce[player][x] == -1 )
- {
- CalcBlobRect( x, y, &myRect );
- SurfaceDrawBlob( player, &myRect, grid[player][x][y], suction[player][x][y], charred[player][x][y] );
- CleanSpriteArea( player, &myRect );
- }
- }
- }
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-}
-
-void BlinkBored( int player )
-{
- MRect myRect;
- int which, x, y, count;
-
- if( GameTickCount() < boredTime[player] )
- return;
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- // undo any previously bored blobs
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- if( ( rowBounce[player][x] == -1 ) &&
- ( suction[player][x][y] == kBlinkBlob || suction[player][x][y] == kSobBlob ) )
- {
- suction[player][x][y] = kNoSuction;
-
- CalcBlobRect( x, y, &myRect );
- SurfaceDrawBlob( player, &myRect, grid[player][x][y],
- suction[player][x][y],
- charred[player][x][y] );
- CleanSpriteArea( player, &myRect );
- }
- }
- }
-
- // make some boredom
-
- which = RandomBefore( 2 );
- boredTime[player] += which? 15: 80;
- which = which? kBlinkBlob: kSobBlob;
-
- for( count=0; count<5; count++ )
- {
- x = RandomBefore( kGridAcross );
- y = RandomBefore( kGridDown );
-
- if( rowBounce[player][x] == -1 &&
- suction[player][x][y] == kNoSuction &&
- grid[player][x][y] >= kFirstBlob &&
- grid[player][x][y] <= kLastBlob
- )
- {
- suction[player][x][y] = which;
-
- CalcBlobRect( x, y, &myRect );
- SurfaceDrawBlob( player, &myRect,
- grid[player][x][y],
- suction[player][x][y],
- charred[player][x][y] );
- CleanSpriteArea( player, &myRect );
- }
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-}
-
-void InitPlayers( void )
-{
- const double windowLoc[ ] = { kLeftPlayerWindowCenter, kRightPlayerWindowCenter };
-
- playerWindowZRect.top = playerWindowZRect.left = 0;
- playerWindowZRect.bottom = 288; playerWindowZRect.right = 144;
-
- playerWindowRect[0] = playerWindowRect[1] = playerWindowZRect;
- CenterRectOnScreen( &playerWindowRect[0], windowLoc[0], 0.5 );
- CenterRectOnScreen( &playerWindowRect[1], windowLoc[1], 0.5 );
-}
--- /dev/null
+++ b/src/prefs.c
@@ -1,0 +1,103 @@
+// prefs.c
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "main.h"
+#include "prefs.h"
+#include "music.h"
+#include "soundfx.h"
+#include "hiscore.h"
+#include "keyselect.h"
+
+typedef struct Preference
+{
+ const char* keyName;
+ void* valuePtr;
+ unsigned int valueLength;
+} Preference;
+
+Preference prefList[] =
+{
+ { "MusicOn", &musicOn, sizeof(MBoolean ) },
+ { "SoundOn", &soundOn, sizeof(MBoolean ) },
+ { "KeyBindings", playerKeys, sizeof(playerKeys ) },
+ { "HighScores", scores, sizeof(scores ) },
+ { "BestCombo", &best, sizeof(best ) },
+ { "Fullscreen", &fullscreen, sizeof(fullscreen ) },
+ { "Widescreen", &widescreen, sizeof(widescreen ) },
+ { "CrispUpscaling", &crispUpscaling, sizeof(crispUpscaling ) },
+};
+
+static FILE* GetPrefsStream(const char* openmode)
+{
+ static char path[1024];
+ const char* userDir = SDL_GetPrefPath(NULL, "CandyCrisis");
+ snprintf(path, sizeof(path), "%sCandyCrisisPrefs.bin", userDir);
+ return fopen(path, openmode);
+}
+
+void LoadPrefs()
+{
+ FILE* stream = GetPrefsStream("rb");
+ if (!stream)
+ {
+ return;
+ }
+
+ for (int i = 0; i < arrsize(prefList); i++)
+ {
+ Preference* pref = &prefList[i];
+
+ fseek(stream, 0, SEEK_SET);
+
+ while (!feof(stream))
+ {
+ int keyLength;
+ char key[256];
+ unsigned int contentsLength;
+
+ keyLength = fgetc(stream);
+ if (keyLength < 0 || feof(stream))
+ break;
+ fread(key, keyLength, 1, stream);
+ key[keyLength] = '\0';
+ fread(&contentsLength, sizeof(contentsLength), 1, stream);
+
+ if (!strncmp(key, pref->keyName, strlen(pref->keyName)))
+ {
+ if (contentsLength != pref->valueLength)
+ break;
+ fread(pref->valuePtr, pref->valueLength, 1, stream);
+ break;
+ }
+ else
+ {
+ fseek(stream, contentsLength, SEEK_CUR);
+ }
+ }
+ }
+
+ fclose(stream);
+}
+
+void SavePrefs()
+{
+ FILE* stream = GetPrefsStream("wb");
+ if (!stream)
+ {
+ return;
+ }
+
+ for (int i = 0; i < arrsize(prefList); i++)
+ {
+ const Preference* pref = &prefList[i];
+ fputc(strlen(pref->keyName), stream);
+ fwrite(pref->keyName, strlen(pref->keyName), 1, stream);
+ fwrite(&pref->valueLength, sizeof(pref->valueLength), 1, stream);
+ fwrite(pref->valuePtr, pref->valueLength, 1, stream);
+ }
+
+ fclose(stream);
+}
--- a/src/prefs.cpp
+++ /dev/null
@@ -1,114 +1,0 @@
-// prefs.c
-
-#include <fstream>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "main.h"
-#include "prefs.h"
-#include "music.h"
-#include "soundfx.h"
-#include "hiscore.h"
-#include "keyselect.h"
-
-struct Preference
-{
- const char* keyName;
- void* valuePtr;
- unsigned int valueLength;
-};
-
-Preference prefList[] =
-{
- { "MusicOn", &musicOn, sizeof(MBoolean ) },
- { "SoundOn", &soundOn, sizeof(MBoolean ) },
- { "KeyBindings", playerKeys, sizeof(playerKeys ) },
- { "HighScores", scores, sizeof(scores ) },
- { "BestCombo", &best, sizeof(best ) },
- { "Fullscreen", &fullscreen, sizeof(fullscreen ) },
- { "Widescreen", &widescreen, sizeof(widescreen ) },
- { "CrispUpscaling", &crispUpscaling, sizeof(crispUpscaling ) },
-};
-
-static std::fstream GetPrefsStream(std::ios::openmode openmode)
-{
- static char path[1024];
- const char* userDir = SDL_GetPrefPath(NULL, "CandyCrisis");
- snprintf(path, sizeof(path), "%sCandyCrisisPrefs.bin", userDir);
-
- return std::fstream(path, std::ios::binary | openmode);
-}
-
-void LoadPrefs()
-{
- std::fstream stream;
- try
- {
- stream = GetPrefsStream(std::ios::in);
- }
- catch (...)
- {
- return;
- }
-
- if (!stream.good())
- {
- return;
- }
-
- for (Preference& pref: prefList)
- {
- stream.seekg(0, std::ios::beg);
- while (stream.good() && !stream.eof())
- {
- int keyLength;
- char key[256];
- unsigned int contentsLength;
-
- keyLength = stream.get();
- if (stream.eof()) break;
- stream.read(key, keyLength);
- key[keyLength] = '\0';
- stream.read((char*)&contentsLength, sizeof(contentsLength));
-
- if (!strncmp(key, pref.keyName, strlen(pref.keyName)))
- {
- if (contentsLength != pref.valueLength)
- break;
- stream.read((char*) pref.valuePtr, pref.valueLength);
- break;
- }
- else
- {
- stream.seekg(contentsLength, std::ios::cur);
- }
- }
- }
-}
-
-void SavePrefs()
-{
- std::fstream stream;
- try
- {
- stream = GetPrefsStream(std::ios::out);
- }
- catch (...)
- {
- return;
- }
-
- if (!stream.good())
- {
- return;
- }
-
- for (Preference& pref: prefList)
- {
- stream.put(strlen(pref.keyName));
- stream.write(pref.keyName, strlen(pref.keyName));
- stream.write((const char*)&pref.valueLength, sizeof(pref.valueLength));
- stream.write((const char*)pref.valuePtr, pref.valueLength);
- }
-}
--- /dev/null
+++ b/src/random.c
@@ -1,0 +1,109 @@
+// random.c
+
+#include <stdlib.h>
+
+#include "main.h"
+#include "random.h"
+
+unsigned int randomSeed[2], pieceCount[2], grenadeTimer[2];
+int pieceMap[kBlobTypes], numPieces;
+
+
+static unsigned int internalRandomSeed = 1;
+
+static int internalRandom() // uses a generic rand() algorithm
+{
+ internalRandomSeed = internalRandomSeed * 1103515245 + 12345;
+ return ((internalRandomSeed >> 16) & 0x7FFF);
+}
+
+
+void InitRandom( int inNumPieces )
+{
+ int count, swap, swapWith;
+
+ numPieces = inNumPieces;
+ randomSeed[0] = randomSeed[1] = SDL_GetTicks();
+ pieceCount[0] = pieceCount[1] = 0;
+ grenadeTimer[0] = grenadeTimer[1] = 40;
+
+ for( count=0; count<kBlobTypes; count++ )
+ {
+ pieceMap[count] = count+1;
+ }
+
+ for( count=0; count<kBlobTypes; count++ )
+ {
+ swapWith = RandomBefore( kBlobTypes );
+ swap = pieceMap[swapWith];
+ pieceMap[swapWith] = pieceMap[count];
+ pieceMap[count] = swap;
+ }
+}
+
+void AddExtraPiece( void )
+{
+ numPieces++;
+}
+
+int GetPiece( int player )
+{
+ int result;
+ unsigned int realSeed;
+
+ realSeed = internalRandomSeed;
+
+ internalRandomSeed = randomSeed[player];
+ result = pieceMap[RandomBefore(numPieces)];
+ randomSeed[player] = internalRandomSeed;
+
+ internalRandomSeed = realSeed;
+
+ return result;
+}
+
+int GetMagic( int player )
+{
+ int result;
+ int realSeed;
+
+ realSeed = internalRandomSeed;
+
+ internalRandomSeed = randomSeed[player];
+ result = (RandomBefore(19) == 0)? true: false;
+ randomSeed[player] = internalRandomSeed;
+
+ internalRandomSeed = realSeed;
+
+ return result;
+}
+
+int GetGrenade( int player )
+{
+ pieceCount[player]++;
+ if( pieceCount[player] == grenadeTimer[player] )
+ {
+ grenadeTimer[player] += grenadeTimer[player] * 3 / 2;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+static inline int RandomRange( double min, double max )
+{
+ const double kMinRand = 0.0;
+ const double kMaxRand = 32767.0;
+ double x;
+
+ x = (internalRandom() - kMinRand) / (kMaxRand - kMinRand + 1.0);
+ return (int) (x * (max + 1.0 - min) + min);
+}
+
+int RandomBefore( int what )
+{
+ return RandomRange( 0.0, what-1 );
+}
+
--- a/src/random.cpp
+++ /dev/null
@@ -1,109 +1,0 @@
-// random.c
-
-#include <stdlib.h>
-
-#include "main.h"
-#include "random.h"
-
-unsigned int randomSeed[2], pieceCount[2], grenadeTimer[2];
-int pieceMap[kBlobTypes], numPieces;
-
-
-static unsigned int internalRandomSeed = 1;
-
-static int internalRandom() // uses a generic rand() algorithm
-{
- internalRandomSeed = internalRandomSeed * 1103515245 + 12345;
- return ((internalRandomSeed >> 16) & 0x7FFF);
-}
-
-
-void InitRandom( int inNumPieces )
-{
- int count, swap, swapWith;
-
- numPieces = inNumPieces;
- randomSeed[0] = randomSeed[1] = SDL_GetTicks();
- pieceCount[0] = pieceCount[1] = 0;
- grenadeTimer[0] = grenadeTimer[1] = 40;
-
- for( count=0; count<kBlobTypes; count++ )
- {
- pieceMap[count] = count+1;
- }
-
- for( count=0; count<kBlobTypes; count++ )
- {
- swapWith = RandomBefore( kBlobTypes );
- swap = pieceMap[swapWith];
- pieceMap[swapWith] = pieceMap[count];
- pieceMap[count] = swap;
- }
-}
-
-void AddExtraPiece( void )
-{
- numPieces++;
-}
-
-int GetPiece( int player )
-{
- int result;
- unsigned int realSeed;
-
- realSeed = internalRandomSeed;
-
- internalRandomSeed = randomSeed[player];
- result = pieceMap[RandomBefore(numPieces)];
- randomSeed[player] = internalRandomSeed;
-
- internalRandomSeed = realSeed;
-
- return result;
-}
-
-int GetMagic( int player )
-{
- int result;
- int realSeed;
-
- realSeed = internalRandomSeed;
-
- internalRandomSeed = randomSeed[player];
- result = (RandomBefore(19) == 0)? true: false;
- randomSeed[player] = internalRandomSeed;
-
- internalRandomSeed = realSeed;
-
- return result;
-}
-
-int GetGrenade( int player )
-{
- pieceCount[player]++;
- if( pieceCount[player] == grenadeTimer[player] )
- {
- grenadeTimer[player] += grenadeTimer[player] * 3 / 2;
- return true;
- }
- else
- {
- return false;
- }
-}
-
-static inline int RandomRange( double min, double max )
-{
- const double kMinRand = 0.0;
- const double kMaxRand = 32767.0;
- double x;
-
- x = (internalRandom() - kMinRand) / (kMaxRand - kMinRand + 1.0);
- return (int) (x * (max + 1.0 - min) + min);
-}
-
-int RandomBefore( int what )
-{
- return RandomRange( 0.0, what-1 );
-}
-
--- /dev/null
+++ b/src/score.c
@@ -1,0 +1,154 @@
+// score.c
+
+#include "SDLU.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "main.h"
+#include "score.h"
+#include "gworld.h"
+#include "graphics.h"
+#include "blitter.h"
+#include "hiscore.h"
+#include "gameticks.h"
+#include "level.h"
+
+SDL_Surface* scoreSurface;
+SDL_Surface* numberSurface;
+SDL_Surface* numberMaskSurface;
+
+
+MRect scoreWindowZRect, scoreWindowRect[2];
+MBoolean scoreWindowVisible[2] = {true, true};
+int roundStartScore[2], score[2], displayedScore[2];
+MTicks scoreTime[2];
+const char characterList[] =
+{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z', '.', '0', '1', '2',
+ '3', '4', '5', '6', '7', '8', '9', '!', '"', '#',
+ '$' };
+
+
+void InitScore( void )
+{
+ const double windowLoc[ ] = { 0.16, 0.84 };
+ SDL_Rect sdlRect;
+
+ scoreWindowZRect.top = scoreWindowZRect.left = 0;
+ scoreWindowZRect.bottom = 32; scoreWindowZRect.right = 144;
+
+ scoreWindowRect[0] = scoreWindowRect[1] = scoreWindowZRect;
+ CenterRectOnScreen( &scoreWindowRect[0], windowLoc[0], 0.89 );
+ CenterRectOnScreen( &scoreWindowRect[1], windowLoc[1], 0.89 );
+
+ scoreSurface = SDLU_InitSurface( SDLU_MRectToSDLRect( &scoreWindowZRect, &sdlRect ), 32 );
+ DrawPICTInSurface( scoreSurface, picBoard );
+
+ numberSurface = LoadPICTAsSurface( picNumber, 32 );
+
+ numberMaskSurface = LoadPICTAsSurface( picNumberMask, MASK_DEPTH );
+
+ displayedScore[0] = displayedScore[1] = 0;
+ score[0] = score[1] = 0;
+ scoreTime[0] = scoreTime[1] = 0;
+}
+
+void UpdateScore( int player )
+{
+ if( GameTickCount( ) >= scoreTime[player] )
+ {
+ scoreTime[player] = GameTickCount() + 1;
+
+ if( displayedScore[player] < score[player] )
+ {
+ if( (score[player] - displayedScore[player]) > 5000 )
+ {
+ displayedScore[player] += 1525;
+ }
+ else if( (score[player] - displayedScore[player]) > 1000 )
+ {
+ displayedScore[player] += 175;
+ }
+ else
+ {
+ displayedScore[player] += 25;
+ }
+
+ if( displayedScore[player] > score[player] )
+ displayedScore[player] = score[player];
+
+ ShowScore( player );
+ }
+ }
+}
+
+void ShowScore( int player )
+{
+ SDL_Rect sourceSDLRect, destSDLRect;
+ MRect myRect;
+ char myString[256];
+ int count;
+
+ if( !scoreWindowVisible[player] ) return;
+
+ if( control[player] != kNobodyControl )
+ {
+ sprintf( myString, "%d", displayedScore[player] );
+
+ SDLU_AcquireSurface( scoreSurface );
+
+ SDLU_BlitSurface( boardSurface[player], &scoreSurface->clip_rect,
+ scoreSurface, &scoreSurface->clip_rect );
+
+ myRect.top = 0;
+ myRect.left = 2;
+ myRect.bottom = kNumberVertSize;
+ myRect.right = myRect.left + kNumberHorizSize;
+ DrawCharacter( kCharacterScore, &myRect );
+ OffsetMRect( &myRect, kNumberHorizSize, 0 );
+ DrawCharacter( kCharacterScore+1, &myRect );
+
+ myRect = scoreWindowZRect;
+ myRect.right -= 2;
+ myRect.left = myRect.right - kNumberHorizSize;
+ for( count = (int) strlen(myString) - 1; count >= 0; count-- )
+ {
+ DrawCharacter( myString[count], &myRect );
+ OffsetMRect( &myRect, -kNumberHorizSize - 1, 0 );
+ }
+
+ SDLU_ReleaseSurface( scoreSurface );
+
+ SDLU_BlitFrontSurface( scoreSurface,
+ SDLU_MRectToSDLRect( &scoreWindowZRect, &sourceSDLRect ),
+ SDLU_MRectToSDLRect( &scoreWindowRect[player], &destSDLRect ) );
+ }
+}
+
+void DrawCharacter( char which, const MRect *myRect )
+{
+ MRect srcRect;
+ int count, result;
+
+ result = -1;
+ for( count = 0; count < arrsize(characterList); count++ )
+ {
+ if( characterList[count] == which )
+ {
+ result = count;
+ break;
+ }
+ }
+
+ if( result == -1 ) return;
+
+ srcRect.top = 0;
+ srcRect.left = result * kNumberHorizSize;
+ srcRect.bottom = kNumberVertSize;
+ srcRect.right = srcRect.left + kNumberHorizSize;
+
+ SurfaceBlitMask( numberSurface, numberMaskSurface, SDLU_GetCurrentSurface(),
+ &srcRect, &srcRect, myRect );
+}
--- a/src/score.cpp
+++ /dev/null
@@ -1,154 +1,0 @@
-// score.c
-
-#include "SDLU.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include "main.h"
-#include "score.h"
-#include "gworld.h"
-#include "graphics.h"
-#include "blitter.h"
-#include "hiscore.h"
-#include "gameticks.h"
-#include "level.h"
-
-SDL_Surface* scoreSurface;
-SDL_Surface* numberSurface;
-SDL_Surface* numberMaskSurface;
-
-
-MRect scoreWindowZRect, scoreWindowRect[2];
-MBoolean scoreWindowVisible[2] = {true, true};
-int roundStartScore[2], score[2], displayedScore[2];
-MTicks scoreTime[2];
-const char characterList[] =
-{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
- 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
- 'U', 'V', 'W', 'X', 'Y', 'Z', '.', '0', '1', '2',
- '3', '4', '5', '6', '7', '8', '9', '!', '"', '#',
- '$' };
-
-
-void InitScore( void )
-{
- const double windowLoc[ ] = { 0.16, 0.84 };
- SDL_Rect sdlRect;
-
- scoreWindowZRect.top = scoreWindowZRect.left = 0;
- scoreWindowZRect.bottom = 32; scoreWindowZRect.right = 144;
-
- scoreWindowRect[0] = scoreWindowRect[1] = scoreWindowZRect;
- CenterRectOnScreen( &scoreWindowRect[0], windowLoc[0], 0.89 );
- CenterRectOnScreen( &scoreWindowRect[1], windowLoc[1], 0.89 );
-
- scoreSurface = SDLU_InitSurface( SDLU_MRectToSDLRect( &scoreWindowZRect, &sdlRect ), 32 );
- DrawPICTInSurface( scoreSurface, picBoard );
-
- numberSurface = LoadPICTAsSurface( picNumber, 32 );
-
- numberMaskSurface = LoadPICTAsSurface( picNumberMask, MASK_DEPTH );
-
- displayedScore[0] = displayedScore[1] = 0;
- score[0] = score[1] = 0;
- scoreTime[0] = scoreTime[1] = 0;
-}
-
-void UpdateScore( int player )
-{
- if( GameTickCount( ) >= scoreTime[player] )
- {
- scoreTime[player] = GameTickCount() + 1;
-
- if( displayedScore[player] < score[player] )
- {
- if( (score[player] - displayedScore[player]) > 5000 )
- {
- displayedScore[player] += 1525;
- }
- else if( (score[player] - displayedScore[player]) > 1000 )
- {
- displayedScore[player] += 175;
- }
- else
- {
- displayedScore[player] += 25;
- }
-
- if( displayedScore[player] > score[player] )
- displayedScore[player] = score[player];
-
- ShowScore( player );
- }
- }
-}
-
-void ShowScore( int player )
-{
- SDL_Rect sourceSDLRect, destSDLRect;
- MRect myRect;
- char myString[256];
- int count;
-
- if( !scoreWindowVisible[player] ) return;
-
- if( control[player] != kNobodyControl )
- {
- sprintf( myString, "%d", displayedScore[player] );
-
- SDLU_AcquireSurface( scoreSurface );
-
- SDLU_BlitSurface( boardSurface[player], &scoreSurface->clip_rect,
- scoreSurface, &scoreSurface->clip_rect );
-
- myRect.top = 0;
- myRect.left = 2;
- myRect.bottom = kNumberVertSize;
- myRect.right = myRect.left + kNumberHorizSize;
- DrawCharacter( kCharacterScore, &myRect );
- OffsetMRect( &myRect, kNumberHorizSize, 0 );
- DrawCharacter( kCharacterScore+1, &myRect );
-
- myRect = scoreWindowZRect;
- myRect.right -= 2;
- myRect.left = myRect.right - kNumberHorizSize;
- for( count = int(strlen(myString)) - 1; count >= 0; count-- )
- {
- DrawCharacter( myString[count], &myRect );
- OffsetMRect( &myRect, -kNumberHorizSize - 1, 0 );
- }
-
- SDLU_ReleaseSurface( scoreSurface );
-
- SDLU_BlitFrontSurface( scoreSurface,
- SDLU_MRectToSDLRect( &scoreWindowZRect, &sourceSDLRect ),
- SDLU_MRectToSDLRect( &scoreWindowRect[player], &destSDLRect ) );
- }
-}
-
-void DrawCharacter( char which, const MRect *myRect )
-{
- MRect srcRect;
- int count, result;
-
- result = -1;
- for( count = 0; count < arrsize(characterList); count++ )
- {
- if( characterList[count] == which )
- {
- result = count;
- break;
- }
- }
-
- if( result == -1 ) return;
-
- srcRect.top = 0;
- srcRect.left = result * kNumberHorizSize;
- srcRect.bottom = kNumberVertSize;
- srcRect.right = srcRect.left + kNumberHorizSize;
-
- SurfaceBlitMask( numberSurface, numberMaskSurface, SDLU_GetCurrentSurface(),
- &srcRect, &srcRect, myRect );
-}
--- a/src/soundfx.cpp
+++ b/src/soundfx.cpp
@@ -1,13 +1,16 @@
// soundfx.c
-#include "main.h"
-#include "soundfx.h"
-#include "music.h"
-
#include "support/cmixer.h"
#include <stdio.h>
-MBoolean soundOn = true;
+extern "C"
+{
+ #include "main.h"
+ #include "soundfx.h"
+ #include "music.h"
+
+ MBoolean soundOn = true;
+}
static std::vector<cmixer::WavStream> s_soundBank;
static constexpr float k_playerStereoSeparation = 0.5f;
--- /dev/null
+++ b/src/tutorial.c
@@ -1,0 +1,500 @@
+// tutorial.c
+
+#include "SDLU.h"
+
+#include "main.h"
+#include "tutorial.h"
+#include "level.h"
+#include "font.h"
+#include "pause.h"
+#include "gworld.h"
+#include "graphics.h"
+#include "control.h"
+#include "blitter.h"
+#include "gameticks.h"
+#include "soundfx.h"
+#include "opponent.h"
+#include "keyselect.h"
+
+#include <string.h>
+#include <stdio.h>
+
+AutoPattern tutorialPattern[] =
+{
+ { kMessage, 0, 0, "Welcome to the\nCandy Crisis\ntutorial!" },
+ { kIdleTicks, 180, 0, NULL },
+ { kMessage, 0, 0, "I'll be your guide\nthroughout the\ntutorial. Let's\nget started!" },
+ { kRetrieve, 1, 1, NULL },
+ { kIdleTicks, 240, 0, NULL },
+ { kMessage, 0, 0, "When you start the\ngame, you'll find a\npair of candies\nfalling from the sky." },
+ { kIdleTicks, 240, 0, NULL },
+ { kMessage, 0, 0, "Your goal is to\nkeep these candies\nfrom overflowing the\nboard!" },
+ { kBlockUntilLand, 0, 0, NULL },
+ { kRetrieve, 2, 2, NULL },
+ { kIdleTicks, 60, 0, NULL },
+ { kMessage, 0, 0, "You control the\ncandy by moving\nthem left and right." },
+ { kIdleTicks, 120, 0, NULL },
+ { kPosition, 0, 0, NULL },
+ { kIdleTicks, 120, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kMessage, 0, 0, "Press '~~'\nto make the pieces\nmove left." },
+ { kRetrieve, 3, 3, NULL },
+ { kIdleTicks, 60, 0, NULL },
+ { kPosition, 5, 0, NULL },
+ { kIdleTicks, 90, 0, NULL },
+ { kMessage, 0, 0, "Use '||' to\nmake the pieces\nmove right." },
+ { kIdleTicks, 180, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kMessage, 0, 0, "You can also\nmake the pieces\nrotate around each\nother." },
+ { kRetrieve, 4, 3, NULL },
+ { kIdleTicks, 180, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kMessage, 0, 0, "Press '{{'\nto make the pieces\nrotate." },
+ { kIdleTicks, 30, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kPosition, 5, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kMessage, 0, 0, "Also, '``'\ncauses the candy\nto drop faster." },
+ { kIdleTicks, 180, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kMessage, 0, 0, "To pause the game\nor adjust settings,\npress 'esc.'" },
+ { kIdleTicks, 280, 0, NULL },
+ { kMessage, 0, 0, "The candy in\nthis game is made\nfrom a highly\nunstable substance!" },
+ { kRetrieve, 2, 2, NULL },
+ { kIdleTicks, 200, 0, NULL },
+ { kMessage, 0, 0, "So when four\npieces of the same\ncolor come into\ncontact..." },
+ { kPosition, 1, 0, NULL },
+ { kIdleTicks, 180, 0, NULL },
+ { kMessage, 0, 0, "... they vaporize!" },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kIdleTicks, 60, 0, NULL },
+ { kMessage, 0, 0, "Let's see that\nonce again." },
+ { kRetrieve, 1, 1, NULL },
+ { kIdleTicks, 120, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kMessage, 0, 0, "Pop!" },
+ { kIdleTicks, 120, 0, NULL },
+ { kMessage, 0, 0, "You can even get\nfive or more\npieces to pop\nall at the same\ntime!" },
+ { kRetrieve, 4, 4, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kPosition, 4, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 4, 4, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kPosition, 3, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 4, 4, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kPosition, 4, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kMessage, 0, 0, "Pop!\n\nTechniques like this\ncan earn lots of\nbonus points." },
+ { kIdleTicks, 180, 0, NULL },
+ { kMessage, 0, 0, "You can also pop\nmore than one color\nat once." },
+ { kRetrieve, 5, 5, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kPosition, 4, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 6, 5, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kPosition, 3, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 3, 5, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 10, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 10, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kPosition, 5, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kMessage, 0, 0, "All right!" },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 0, 6, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kMessage, 0, 0, "You can even set\nup devastating\nchain reactions..." },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 0, 6, NULL },
+ { kIdleTicks, 90, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 6, 6, NULL },
+ { kIdleTicks, 60, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kPosition, 1, 0, NULL },
+ { kMessage, 0, 0, "... like this!" },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kMessage, 0, 0, "Tricky, isn't it?" },
+ { kRetrieve, 1, 2, NULL },
+ { kIdleTicks, 60, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 1, 2, NULL },
+ { kIdleTicks, 60, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 3, 1, NULL },
+ { kIdleTicks, 60, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 3, 2, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kPosition, 3, 0, NULL },
+ { kMessage, 0, 0, "Let's see one more\nexample of a chain\nreaction." },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 1, 2, NULL },
+ { kIdleTicks, 60, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 5, 5, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kPosition, 1, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 5, 3, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 10, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 10, 0, NULL },
+ { kPosition, 1, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 3, 5, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kPosition, 0, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 10, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 3, 3, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kPosition, 0, 0, NULL },
+ { kIdleTicks, 20, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kIdleTicks, 90, 0, NULL },
+ { kMessage, 0, 0, "There's one more\nthing you need to\nknow about..." },
+ { kIdleTicks, 180, 0, NULL },
+ { kMessage, 0, 0, "Watch out for the\nsee-through candy!" },
+ { kIdleTicks, 60, 0, NULL },
+ { kPunish, 18, 0, NULL },
+ { kRetrieve, 1, 1, NULL },
+ { kIdleTicks, 120, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kPosition, 0, 0, NULL },
+ { kIdleTicks, 20, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kMessage, 0, 0, "When your opponent\nvaporizes a group of\ncandies, they also\nsend some transparent\npieces to you!" },
+ { kRetrieve, 1, 1, NULL },
+ { kIdleTicks, 90, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kPosition, 4, 0, NULL },
+ { kIdleTicks, 30, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 1, 1, NULL },
+ { kIdleTicks, 60, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 90, 0, NULL },
+ { kMessage, 0, 0, "You can get rid of\nthese pieces by\nvaporizing something\nnext to them." },
+ { kIdleTicks, 150, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kIdleTicks, 60, 0, NULL },
+ { kRetrieve, 1, 2, NULL },
+ { kMessage, 0, 0, "There are also\nsome bonus items\nwhich can come\nin handy." },
+ { kIdleTicks, 20, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kPosition, 0, 0, NULL },
+ { kIdleTicks, 20, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 3, 1, NULL },
+ { kIdleTicks, 20, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 10, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 10, 0, NULL },
+ { kPosition, 0, 0, NULL },
+ { kIdleTicks, 20, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 1, 3, NULL },
+ { kIdleTicks, 10, 0, NULL },
+ { kPosition, 1, 0, NULL },
+ { kIdleTicks, 15, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kMessage, 0, 0, "One of these bonus\nitems is the Crazy\nCandy!" },
+ { kRetrieve, -1, 2, NULL },
+ { kIdleTicks, 15, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 10, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 100, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kMessage, 0, 0, "The Crazy Candy\ntakes on the\ncolor of one of\nits neighbors." },
+ { kIdleTicks, 60, 0, NULL },
+ { kRetrieve, 3, 4, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kPosition, 4, 0, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 1, 5, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kPosition, 1, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kMessage, 0, 0, "Another useful bonus\nitem is the bomb!" },
+ { kRetrieve, 2, 3, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kPosition, 0, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 0, 3, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 3, 2, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kPosition, 5, 0, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 4, 3, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kPosition, 3, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, 2, 3, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kSpin, 0, 0, NULL },
+ { kIdleTicks, 5, 0, NULL },
+ { kPosition, 5, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kRetrieve, kBombBottom, kBombTop, NULL },
+ { kMessage, 0, 0, "When the bomb lands\non one color\nof candy, all\npieces of that\ncolor will\nvaporize!" },
+ { kIdleTicks, 100, 0, NULL },
+ { kPosition, 4, 0, NULL },
+ { kIdleTicks, 120, 0, NULL },
+ { kBlockUntilDrop, 0, 0, NULL },
+ { kIdleTicks, 200, 0, NULL },
+ { kMessage, 0, 0, "Now you're ready\nto play Candy Crisis.\nGood luck!" },
+ { kIdleTicks, 270, 0, NULL },
+
+ { kComplete, 0, 0, NULL }
+};
+
+MRect balloonRect = {0, 0, 208, 236};
+SkittlesFontPtr balloonFont;
+MPoint balloonPt;
+char* balloonChar;
+char balloonMsg[256];
+MTicks balloonTime, tutorialTime;
+SDL_Surface* balloonSurface = NULL;
+
+void InitTutorial( void )
+{
+ // Balloon font
+ balloonFont = GetFont( picBalloonFont );
+
+ // Balloon backbuffer
+ if( balloonSurface == NULL )
+ {
+ SDL_Rect surfaceRect = { 0, 0, backdropSurface->w, backdropSurface->h };
+ balloonSurface = SDLU_InitSurface( &surfaceRect, 32 );
+ }
+
+ // Set up auto pattern
+ autoPattern = tutorialPattern;
+ tutorialTime = 0;
+}
+
+void EndTutorial( void )
+{
+ QuickFadeOut( NULL );
+
+ showStartMenu = true;
+}
+
+static int CalculateBalloonWidth( char *message )
+{
+ int maxWidth = 40;
+ int currentWidth = 0;
+
+ for( ;; )
+ {
+ char in = *message++;
+
+ switch(in)
+ {
+ case 0:
+ return (currentWidth > maxWidth)? currentWidth: maxWidth;
+
+ case '\n':
+ maxWidth = (currentWidth > maxWidth)? currentWidth: maxWidth;
+ currentWidth = 0;
+ break;
+
+ default:
+ currentWidth += balloonFont->width[(uint8_t) in];
+ break;
+ }
+ }
+}
+
+static int CalculateBalloonHeight( char *message )
+{
+ int lines = 2;
+ char *scan = message;
+
+ while( *scan ) lines += (*scan++ == '\n');
+
+ return lines * 20;
+}
+
+void StopBalloon( void )
+{
+ balloonTime = 0x7FFFFFFF;
+}
+
+void StartBalloon( const char *message )
+{
+ MPoint balloonTip, balloonFill;
+ int replace;
+ const char* match[] = { "~~", "||", "``", "{{" };
+ char* search;
+ SDL_Rect balloonSDLRect, balloonContentsSDLRect;
+ MRect balloonContentsRect;
+
+ strcpy( balloonMsg, message );
+ for( replace=0; replace<4; replace++ )
+ {
+ search = strstr( balloonMsg, match[replace] );
+ if( search )
+ {
+ char temp[256];
+
+ search[0] = '%';
+ search[1] = 's';
+ sprintf( temp, balloonMsg, SDL_GetKeyName( playerKeys[1][replace] ) );
+ strcpy( balloonMsg, temp );
+ }
+ }
+
+ // Erase previous balloons
+ SDLU_MRectToSDLRect( &balloonRect, &balloonSDLRect );
+ SDLU_BlitFrontSurface( backdropSurface, &balloonSDLRect, &balloonSDLRect );
+
+ // Draw empty balloon outline
+ SDLU_AcquireSurface( balloonSurface );
+
+ balloonRect.left = balloonRect.right - 25 - CalculateBalloonWidth ( balloonMsg );
+ balloonRect.top = balloonRect.bottom - 25 - CalculateBalloonHeight( balloonMsg );
+
+ SDLU_MRectToSDLRect( &balloonRect, &balloonSDLRect );
+ SDLU_BlitSurface( backdropSurface, &balloonSDLRect,
+ balloonSurface, &balloonSDLRect );
+
+ balloonContentsRect = balloonRect;
+ balloonContentsRect.bottom -= 25;
+
+ SurfaceGetEdges( balloonSurface, &balloonContentsRect );
+ SDL_FillRect( balloonSurface,
+ SDLU_MRectToSDLRect( &balloonContentsRect, &balloonContentsSDLRect ),
+ SDL_MapRGB( balloonSurface->format, 0xFF, 0xFF, 0xFF ) );
+ SurfaceCurveEdges( balloonSurface, &balloonContentsRect );
+
+ balloonTip.v = balloonContentsRect.bottom - 2;
+ balloonTip.h = balloonContentsRect.right - 60;
+ balloonFill = balloonTip;
+
+ SurfaceBlitCharacter( balloonFont, '\x01', &balloonFill, 0, 0, 0, 0 );
+ SurfaceBlitCharacter( balloonFont, '\x02', &balloonTip, 255, 255, 255, 0 );
+
+ SDLU_ReleaseSurface( balloonSurface );
+
+ // Blit empty balloon to screen
+ SDLU_MRectToSDLRect( &balloonRect, &balloonSDLRect );
+ SDLU_BlitFrontSurface( balloonSurface, &balloonSDLRect, &balloonSDLRect );
+
+ balloonPt.h = balloonRect.left + 10;
+ balloonPt.v = balloonRect.top + 10;
+ balloonChar = balloonMsg;
+ balloonTime = GameTickCount( );
+
+ OpponentChatter( true );
+}
+
+void UpdateBalloon( void )
+{
+ SDL_Rect balloonSDLRect;
+
+ if( control[0] != kAutoControl ) return;
+ if( GameTickCount() < balloonTime ) return;
+
+ if( balloonChar )
+ {
+ unsigned char in = *balloonChar++;
+
+ switch( in )
+ {
+ case 0:
+ OpponentChatter( false );
+ balloonChar = NULL;
+ balloonTime += 120;
+ break;
+
+ case '\n':
+ balloonPt.h = balloonRect.left + 10;
+ balloonPt.v += 20;
+ break;
+
+ default:
+ if( balloonFont->width[in] > 0 )
+ {
+ SDLU_AcquireSurface( balloonSurface );
+ SurfaceBlitCharacter( balloonFont, in, &balloonPt, 0, 0, 0, 0 );
+ SDLU_ReleaseSurface( balloonSurface );
+
+ SDLU_MRectToSDLRect( &balloonRect, &balloonSDLRect );
+ SDLU_BlitFrontSurface( balloonSurface, &balloonSDLRect, &balloonSDLRect );
+
+ balloonTime += 2;
+ }
+ break;
+ }
+ }
+ else
+ {
+ SDLU_MRectToSDLRect( &balloonRect, &balloonSDLRect );
+ SDLU_BlitFrontSurface( backdropSurface, &balloonSDLRect, &balloonSDLRect );
+
+ StopBalloon();
+ }
+}
--- a/src/tutorial.cpp
+++ /dev/null
@@ -1,500 +1,0 @@
-// tutorial.c
-
-#include "SDLU.h"
-
-#include "main.h"
-#include "tutorial.h"
-#include "level.h"
-#include "font.h"
-#include "pause.h"
-#include "gworld.h"
-#include "graphics.h"
-#include "control.h"
-#include "blitter.h"
-#include "gameticks.h"
-#include "soundfx.h"
-#include "opponent.h"
-#include "keyselect.h"
-
-#include <string.h>
-#include <stdio.h>
-
-AutoPattern tutorialPattern[] =
-{
- { kMessage, 0, 0, "Welcome to the\nCandy Crisis\ntutorial!" },
- { kIdleTicks, 180, 0, NULL },
- { kMessage, 0, 0, "I'll be your guide\nthroughout the\ntutorial. Let's\nget started!" },
- { kRetrieve, 1, 1, NULL },
- { kIdleTicks, 240, 0, NULL },
- { kMessage, 0, 0, "When you start the\ngame, you'll find a\npair of candies\nfalling from the sky." },
- { kIdleTicks, 240, 0, NULL },
- { kMessage, 0, 0, "Your goal is to\nkeep these candies\nfrom overflowing the\nboard!" },
- { kBlockUntilLand, 0, 0, NULL },
- { kRetrieve, 2, 2, NULL },
- { kIdleTicks, 60, 0, NULL },
- { kMessage, 0, 0, "You control the\ncandy by moving\nthem left and right." },
- { kIdleTicks, 120, 0, NULL },
- { kPosition, 0, 0, NULL },
- { kIdleTicks, 120, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kMessage, 0, 0, "Press '~~'\nto make the pieces\nmove left." },
- { kRetrieve, 3, 3, NULL },
- { kIdleTicks, 60, 0, NULL },
- { kPosition, 5, 0, NULL },
- { kIdleTicks, 90, 0, NULL },
- { kMessage, 0, 0, "Use '||' to\nmake the pieces\nmove right." },
- { kIdleTicks, 180, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kMessage, 0, 0, "You can also\nmake the pieces\nrotate around each\nother." },
- { kRetrieve, 4, 3, NULL },
- { kIdleTicks, 180, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kMessage, 0, 0, "Press '{{'\nto make the pieces\nrotate." },
- { kIdleTicks, 30, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kPosition, 5, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kMessage, 0, 0, "Also, '``'\ncauses the candy\nto drop faster." },
- { kIdleTicks, 180, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kMessage, 0, 0, "To pause the game\nor adjust settings,\npress 'esc.'" },
- { kIdleTicks, 280, 0, NULL },
- { kMessage, 0, 0, "The candy in\nthis game is made\nfrom a highly\nunstable substance!" },
- { kRetrieve, 2, 2, NULL },
- { kIdleTicks, 200, 0, NULL },
- { kMessage, 0, 0, "So when four\npieces of the same\ncolor come into\ncontact..." },
- { kPosition, 1, 0, NULL },
- { kIdleTicks, 180, 0, NULL },
- { kMessage, 0, 0, "... they vaporize!" },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kIdleTicks, 60, 0, NULL },
- { kMessage, 0, 0, "Let's see that\nonce again." },
- { kRetrieve, 1, 1, NULL },
- { kIdleTicks, 120, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kMessage, 0, 0, "Pop!" },
- { kIdleTicks, 120, 0, NULL },
- { kMessage, 0, 0, "You can even get\nfive or more\npieces to pop\nall at the same\ntime!" },
- { kRetrieve, 4, 4, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kPosition, 4, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 4, 4, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kPosition, 3, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 4, 4, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kPosition, 4, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kMessage, 0, 0, "Pop!\n\nTechniques like this\ncan earn lots of\nbonus points." },
- { kIdleTicks, 180, 0, NULL },
- { kMessage, 0, 0, "You can also pop\nmore than one color\nat once." },
- { kRetrieve, 5, 5, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kPosition, 4, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 6, 5, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kPosition, 3, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 3, 5, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 10, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 10, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kPosition, 5, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kMessage, 0, 0, "All right!" },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 0, 6, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kMessage, 0, 0, "You can even set\nup devastating\nchain reactions..." },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 0, 6, NULL },
- { kIdleTicks, 90, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 6, 6, NULL },
- { kIdleTicks, 60, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kPosition, 1, 0, NULL },
- { kMessage, 0, 0, "... like this!" },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kMessage, 0, 0, "Tricky, isn't it?" },
- { kRetrieve, 1, 2, NULL },
- { kIdleTicks, 60, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 1, 2, NULL },
- { kIdleTicks, 60, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 3, 1, NULL },
- { kIdleTicks, 60, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 3, 2, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kPosition, 3, 0, NULL },
- { kMessage, 0, 0, "Let's see one more\nexample of a chain\nreaction." },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 1, 2, NULL },
- { kIdleTicks, 60, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 5, 5, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kPosition, 1, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 5, 3, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 10, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 10, 0, NULL },
- { kPosition, 1, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 3, 5, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kPosition, 0, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 10, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 3, 3, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kPosition, 0, 0, NULL },
- { kIdleTicks, 20, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kIdleTicks, 90, 0, NULL },
- { kMessage, 0, 0, "There's one more\nthing you need to\nknow about..." },
- { kIdleTicks, 180, 0, NULL },
- { kMessage, 0, 0, "Watch out for the\nsee-through candy!" },
- { kIdleTicks, 60, 0, NULL },
- { kPunish, 18, 0, NULL },
- { kRetrieve, 1, 1, NULL },
- { kIdleTicks, 120, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kPosition, 0, 0, NULL },
- { kIdleTicks, 20, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kMessage, 0, 0, "When your opponent\nvaporizes a group of\ncandies, they also\nsend some transparent\npieces to you!" },
- { kRetrieve, 1, 1, NULL },
- { kIdleTicks, 90, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kPosition, 4, 0, NULL },
- { kIdleTicks, 30, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 1, 1, NULL },
- { kIdleTicks, 60, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 90, 0, NULL },
- { kMessage, 0, 0, "You can get rid of\nthese pieces by\nvaporizing something\nnext to them." },
- { kIdleTicks, 150, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kIdleTicks, 60, 0, NULL },
- { kRetrieve, 1, 2, NULL },
- { kMessage, 0, 0, "There are also\nsome bonus items\nwhich can come\nin handy." },
- { kIdleTicks, 20, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kPosition, 0, 0, NULL },
- { kIdleTicks, 20, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 3, 1, NULL },
- { kIdleTicks, 20, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 10, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 10, 0, NULL },
- { kPosition, 0, 0, NULL },
- { kIdleTicks, 20, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 1, 3, NULL },
- { kIdleTicks, 10, 0, NULL },
- { kPosition, 1, 0, NULL },
- { kIdleTicks, 15, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kMessage, 0, 0, "One of these bonus\nitems is the Crazy\nCandy!" },
- { kRetrieve, -1, 2, NULL },
- { kIdleTicks, 15, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 10, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 100, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kMessage, 0, 0, "The Crazy Candy\ntakes on the\ncolor of one of\nits neighbors." },
- { kIdleTicks, 60, 0, NULL },
- { kRetrieve, 3, 4, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kPosition, 4, 0, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 1, 5, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kPosition, 1, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kMessage, 0, 0, "Another useful bonus\nitem is the bomb!" },
- { kRetrieve, 2, 3, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kPosition, 0, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 0, 3, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 3, 2, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kPosition, 5, 0, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 4, 3, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kPosition, 3, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, 2, 3, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kSpin, 0, 0, NULL },
- { kIdleTicks, 5, 0, NULL },
- { kPosition, 5, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kRetrieve, kBombBottom, kBombTop, NULL },
- { kMessage, 0, 0, "When the bomb lands\non one color\nof candy, all\npieces of that\ncolor will\nvaporize!" },
- { kIdleTicks, 100, 0, NULL },
- { kPosition, 4, 0, NULL },
- { kIdleTicks, 120, 0, NULL },
- { kBlockUntilDrop, 0, 0, NULL },
- { kIdleTicks, 200, 0, NULL },
- { kMessage, 0, 0, "Now you're ready\nto play Candy Crisis.\nGood luck!" },
- { kIdleTicks, 270, 0, NULL },
-
- { kComplete, 0, 0, NULL }
-};
-
-MRect balloonRect = {0, 0, 208, 236};
-SkittlesFontPtr balloonFont;
-MPoint balloonPt;
-char* balloonChar;
-char balloonMsg[256];
-MTicks balloonTime, tutorialTime;
-SDL_Surface* balloonSurface = NULL;
-
-void InitTutorial( void )
-{
- // Balloon font
- balloonFont = GetFont( picBalloonFont );
-
- // Balloon backbuffer
- if( balloonSurface == NULL )
- {
- SDL_Rect surfaceRect = { 0, 0, backdropSurface->w, backdropSurface->h };
- balloonSurface = SDLU_InitSurface( &surfaceRect, 32 );
- }
-
- // Set up auto pattern
- autoPattern = tutorialPattern;
- tutorialTime = 0;
-}
-
-void EndTutorial( void )
-{
- QuickFadeOut( NULL );
-
- showStartMenu = true;
-}
-
-static int CalculateBalloonWidth( char *message )
-{
- int maxWidth = 40;
- int currentWidth = 0;
-
- for( ;; )
- {
- char in = *message++;
-
- switch(in)
- {
- case 0:
- return (currentWidth > maxWidth)? currentWidth: maxWidth;
-
- case '\n':
- maxWidth = (currentWidth > maxWidth)? currentWidth: maxWidth;
- currentWidth = 0;
- break;
-
- default:
- currentWidth += balloonFont->width[(uint8_t) in];
- break;
- }
- }
-}
-
-static int CalculateBalloonHeight( char *message )
-{
- int lines = 2;
- char *scan = message;
-
- while( *scan ) lines += (*scan++ == '\n');
-
- return lines * 20;
-}
-
-void StopBalloon( void )
-{
- balloonTime = 0x7FFFFFFF;
-}
-
-void StartBalloon( const char *message )
-{
- MPoint balloonTip, balloonFill;
- int replace;
- const char* match[] = { "~~", "||", "``", "{{" };
- char* search;
- SDL_Rect balloonSDLRect, balloonContentsSDLRect;
- MRect balloonContentsRect;
-
- strcpy( balloonMsg, message );
- for( replace=0; replace<4; replace++ )
- {
- search = strstr( balloonMsg, match[replace] );
- if( search )
- {
- char temp[256];
-
- search[0] = '%';
- search[1] = 's';
- sprintf( temp, balloonMsg, SDL_GetKeyName( playerKeys[1][replace] ) );
- strcpy( balloonMsg, temp );
- }
- }
-
- // Erase previous balloons
- SDLU_MRectToSDLRect( &balloonRect, &balloonSDLRect );
- SDLU_BlitFrontSurface( backdropSurface, &balloonSDLRect, &balloonSDLRect );
-
- // Draw empty balloon outline
- SDLU_AcquireSurface( balloonSurface );
-
- balloonRect.left = balloonRect.right - 25 - CalculateBalloonWidth ( balloonMsg );
- balloonRect.top = balloonRect.bottom - 25 - CalculateBalloonHeight( balloonMsg );
-
- SDLU_MRectToSDLRect( &balloonRect, &balloonSDLRect );
- SDLU_BlitSurface( backdropSurface, &balloonSDLRect,
- balloonSurface, &balloonSDLRect );
-
- balloonContentsRect = balloonRect;
- balloonContentsRect.bottom -= 25;
-
- SurfaceGetEdges( balloonSurface, &balloonContentsRect );
- SDL_FillRect( balloonSurface,
- SDLU_MRectToSDLRect( &balloonContentsRect, &balloonContentsSDLRect ),
- SDL_MapRGB( balloonSurface->format, 0xFF, 0xFF, 0xFF ) );
- SurfaceCurveEdges( balloonSurface, &balloonContentsRect );
-
- balloonTip.v = balloonContentsRect.bottom - 2;
- balloonTip.h = balloonContentsRect.right - 60;
- balloonFill = balloonTip;
-
- SurfaceBlitCharacter( balloonFont, '\x01', &balloonFill, 0, 0, 0, 0 );
- SurfaceBlitCharacter( balloonFont, '\x02', &balloonTip, 255, 255, 255, 0 );
-
- SDLU_ReleaseSurface( balloonSurface );
-
- // Blit empty balloon to screen
- SDLU_MRectToSDLRect( &balloonRect, &balloonSDLRect );
- SDLU_BlitFrontSurface( balloonSurface, &balloonSDLRect, &balloonSDLRect );
-
- balloonPt.h = balloonRect.left + 10;
- balloonPt.v = balloonRect.top + 10;
- balloonChar = balloonMsg;
- balloonTime = GameTickCount( );
-
- OpponentChatter( true );
-}
-
-void UpdateBalloon( void )
-{
- SDL_Rect balloonSDLRect;
-
- if( control[0] != kAutoControl ) return;
- if( GameTickCount() < balloonTime ) return;
-
- if( balloonChar )
- {
- unsigned char in = *balloonChar++;
-
- switch( in )
- {
- case 0:
- OpponentChatter( false );
- balloonChar = NULL;
- balloonTime += 120;
- break;
-
- case '\n':
- balloonPt.h = balloonRect.left + 10;
- balloonPt.v += 20;
- break;
-
- default:
- if( balloonFont->width[in] > 0 )
- {
- SDLU_AcquireSurface( balloonSurface );
- SurfaceBlitCharacter( balloonFont, in, &balloonPt, 0, 0, 0, 0 );
- SDLU_ReleaseSurface( balloonSurface );
-
- SDLU_MRectToSDLRect( &balloonRect, &balloonSDLRect );
- SDLU_BlitFrontSurface( balloonSurface, &balloonSDLRect, &balloonSDLRect );
-
- balloonTime += 2;
- }
- break;
- }
- }
- else
- {
- SDLU_MRectToSDLRect( &balloonRect, &balloonSDLRect );
- SDLU_BlitFrontSurface( backdropSurface, &balloonSDLRect, &balloonSDLRect );
-
- StopBalloon();
- }
-}
--- /dev/null
+++ b/src/tweak.c
@@ -1,0 +1,128 @@
+// tweak.c
+
+#include <math.h>
+
+#include "main.h"
+#include "tweak.h"
+#include "gworld.h"
+#include "moving.h"
+#include "gameticks.h"
+#include "graphics.h"
+#include "players.h"
+
+MTicks xTweakTime[2], yTweakTime[2], rTweakTime[2];
+int yTweak[2], xTweak[2], xDirection[2], rTweak[2], rDirection[2];
+int lastShadow[2];
+int tweakOffsetX[4][11], tweakOffsetY[4][11];
+
+void InitTweak( void )
+{
+ int rTweakValues[] = { 0, 5, 10, 30, 50, 70, 90, 110, 130, 150, 170 };
+ int count, rotate;
+ double tweakRad;
+
+ for( rotate = 0; rotate<2; rotate++ )
+ {
+ for( count=0; count<=10; count++ )
+ {
+ tweakRad = d2r( (90*rotate) - rTweakValues[count] );
+ tweakOffsetX[rotate][count] = (int) floor( 0.5 + cos( tweakRad ) * kBlobHorizSize );
+ tweakOffsetY[rotate][count] = (int) floor( 0.5 + sin( tweakRad ) * kBlobVertSize );
+
+ tweakOffsetX[rotate+2][count] = -tweakOffsetX[rotate][count];
+ tweakOffsetY[rotate+2][count] = -tweakOffsetY[rotate][count];
+ }
+ }
+}
+
+void TweakFirstBlob( int player, MRect *first )
+{
+ int tweakValues[] = {0, -1, -2, -3, -6, -12};
+
+ if( xTweak[player] > 0 )
+ {
+ OffsetMRect( first, xDirection[player] * tweakValues[xTweak[player]], 0 );
+ }
+
+ if( yTweak[player] > 0 )
+ {
+ OffsetMRect( first, 0, tweakValues[yTweak[player]] );
+ }
+}
+
+void TweakSecondBlob( int player, MRect *second )
+{
+ int x, y;
+
+ CalcSecondBlobOffset( player, &x, &y );
+ OffsetMRect( second,
+ tweakOffsetX[blobR[player]][rTweak[player]],
+ tweakOffsetY[blobR[player]][rTweak[player]] );
+}
+
+void StartTweak( int player, int direction, int rotate, int fall )
+{
+ if( fall != 0 )
+ {
+ yTweak[player] = 3;
+ yTweakTime[player] = GameTickCount() + kTweakDelay;
+ }
+
+ if( direction != 0 )
+ {
+ xDirection[player] = direction;
+ xTweak[player] = 5;
+ xTweakTime[player] = GameTickCount() + kTweakDelay;
+ }
+
+ if( rotate != 0 )
+ {
+ rTweak[player] = rotate * 5;
+ rDirection[player] = rotate;
+ rTweakTime[player] = GameTickCount() + kTweakDelay;
+ }
+}
+
+void UpdateTweak( int player, int animation )
+{
+ MBoolean isXTweaked, isYTweaked, isRTweaked, isAnimTweaked = false;
+
+ if( GameTickCount( ) >= animTime[player] )
+ {
+ isAnimTweaked = true;
+ animTime[player] += 2;
+ anim[player]++;
+
+ HandleMagic( player );
+ }
+
+ isXTweaked = ( (GameTickCount() >= xTweakTime[player]) && (xTweak[player] > 0) );
+ isYTweaked = ( (GameTickCount() >= yTweakTime[player]) && (yTweak[player] > 0) );
+ isRTweaked = ( (GameTickCount() >= rTweakTime[player]) && (rTweak[player] > 0) );
+
+ if( isXTweaked || isRTweaked || isYTweaked ||
+ isAnimTweaked || (shadowDepth[player] != lastShadow[player]) )
+ {
+ EraseSpriteBlobs( player );
+
+ if( isXTweaked )
+ {
+ xTweak[player]--;
+ xTweakTime[player] += kTweakDelay;
+ }
+
+ if( isYTweaked )
+ {
+ yTweak[player]--;
+ yTweakTime[player] += kTweakDelay;
+ }
+
+ if( isRTweaked )
+ {
+ rTweak[player]--;
+ rTweakTime[player] += kTweakDelay;
+ }
+
+ DrawSpriteBlobs( player, animation );
+ }
+}
--- a/src/tweak.cpp
+++ /dev/null
@@ -1,128 +1,0 @@
-// tweak.c
-
-#include <math.h>
-
-#include "main.h"
-#include "tweak.h"
-#include "gworld.h"
-#include "moving.h"
-#include "gameticks.h"
-#include "graphics.h"
-#include "players.h"
-
-MTicks xTweakTime[2], yTweakTime[2], rTweakTime[2];
-int yTweak[2], xTweak[2], xDirection[2], rTweak[2], rDirection[2];
-int lastShadow[2];
-int tweakOffsetX[4][11], tweakOffsetY[4][11];
-
-void InitTweak( void )
-{
- int rTweakValues[] = { 0, 5, 10, 30, 50, 70, 90, 110, 130, 150, 170 };
- int count, rotate;
- double tweakRad;
-
- for( rotate = 0; rotate<2; rotate++ )
- {
- for( count=0; count<=10; count++ )
- {
- tweakRad = d2r( (90*rotate) - rTweakValues[count] );
- tweakOffsetX[rotate][count] = (int) floor( 0.5 + cos( tweakRad ) * kBlobHorizSize );
- tweakOffsetY[rotate][count] = (int) floor( 0.5 + sin( tweakRad ) * kBlobVertSize );
-
- tweakOffsetX[rotate+2][count] = -tweakOffsetX[rotate][count];
- tweakOffsetY[rotate+2][count] = -tweakOffsetY[rotate][count];
- }
- }
-}
-
-void TweakFirstBlob( int player, MRect *first )
-{
- int tweakValues[] = {0, -1, -2, -3, -6, -12};
-
- if( xTweak[player] > 0 )
- {
- OffsetMRect( first, xDirection[player] * tweakValues[xTweak[player]], 0 );
- }
-
- if( yTweak[player] > 0 )
- {
- OffsetMRect( first, 0, tweakValues[yTweak[player]] );
- }
-}
-
-void TweakSecondBlob( int player, MRect *second )
-{
- int x, y;
-
- CalcSecondBlobOffset( player, &x, &y );
- OffsetMRect( second,
- tweakOffsetX[blobR[player]][rTweak[player]],
- tweakOffsetY[blobR[player]][rTweak[player]] );
-}
-
-void StartTweak( int player, int direction, int rotate, int fall )
-{
- if( fall != 0 )
- {
- yTweak[player] = 3;
- yTweakTime[player] = GameTickCount() + kTweakDelay;
- }
-
- if( direction != 0 )
- {
- xDirection[player] = direction;
- xTweak[player] = 5;
- xTweakTime[player] = GameTickCount() + kTweakDelay;
- }
-
- if( rotate != 0 )
- {
- rTweak[player] = rotate * 5;
- rDirection[player] = rotate;
- rTweakTime[player] = GameTickCount() + kTweakDelay;
- }
-}
-
-void UpdateTweak( int player, int animation )
-{
- MBoolean isXTweaked, isYTweaked, isRTweaked, isAnimTweaked = false;
-
- if( GameTickCount( ) >= animTime[player] )
- {
- isAnimTweaked = true;
- animTime[player] += 2;
- anim[player]++;
-
- HandleMagic( player );
- }
-
- isXTweaked = ( (GameTickCount() >= xTweakTime[player]) && (xTweak[player] > 0) );
- isYTweaked = ( (GameTickCount() >= yTweakTime[player]) && (yTweak[player] > 0) );
- isRTweaked = ( (GameTickCount() >= rTweakTime[player]) && (rTweak[player] > 0) );
-
- if( isXTweaked || isRTweaked || isYTweaked ||
- isAnimTweaked || (shadowDepth[player] != lastShadow[player]) )
- {
- EraseSpriteBlobs( player );
-
- if( isXTweaked )
- {
- xTweak[player]--;
- xTweakTime[player] += kTweakDelay;
- }
-
- if( isYTweaked )
- {
- yTweak[player]--;
- yTweakTime[player] += kTweakDelay;
- }
-
- if( isRTweaked )
- {
- rTweak[player]--;
- rTweakTime[player] += kTweakDelay;
- }
-
- DrawSpriteBlobs( player, animation );
- }
-}
--- a/src/tweak.h
+++ b/src/tweak.h
@@ -6,6 +6,6 @@
void UpdateTweak( int player, int suction );
void InitTweak( void );
-#define d2r(x) ((x)*(pi/180))
+#define d2r(x) ((x)*(kPi/180))
#define kTweakDelay 1
--- /dev/null
+++ b/src/victory.c
@@ -1,0 +1,344 @@
+// victory.c
+
+#include "SDLU.h"
+
+#include "main.h"
+#include "victory.h"
+#include "players.h"
+#include "gworld.h"
+#include "grays.h"
+#include "graphics.h"
+#include "soundfx.h"
+#include "score.h"
+#include "control.h"
+#include "random.h"
+#include "tweak.h"
+#include "gameticks.h"
+#include "level.h"
+#include "blitter.h"
+#include "music.h"
+#include "hiscore.h"
+#include "keyselect.h"
+#include "zap.h"
+#include "pause.h"
+#include "font.h"
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+MTicks winTime, loseTime;
+int winStage, loseStage;
+float drop[kGridAcross], last[kGridAcross];
+SkittlesFontPtr victoryFont;
+
+void InitVictory( void )
+{
+ victoryFont = GetFont( picVictoryFont );
+}
+
+void EndRound( int player )
+{
+ int count;
+
+ loseTime = GameTickCount( );
+ loseStage = 0;
+
+ role[player] = kLosing;
+ emotions[player] = kEmotionPanic;
+
+ for( count=0; count<kGridAcross; count++ )
+ {
+ last[count] = 0.1f;
+ drop[count] = 0.4f + RandomBefore(1000)/20000;
+ rowBounce[player][count] = 99;
+ }
+
+ if( player == 0 )
+ {
+ ChooseMusic( -1 );
+ PlayMono( kLoss );
+ }
+}
+
+void BeginVictory( int player )
+{
+ int count;
+
+ endTime = GameTickCount( );
+ winTime = GameTickCount( );
+ winStage = 0;
+
+ role[player] = kWinning;
+ emotions[player] = kEmotionHappy;
+
+ EraseSpriteBlobs( player );
+
+ for( count=0; count<kGridAcross; count++ )
+ {
+ rowBounce[player][count] = 99;
+ }
+
+ if( player == 0 )
+ {
+ ChooseMusic( -1 );
+ PlayMono( kVictory );
+ }
+}
+
+void Lose( int player )
+{
+ MTicks gameTime = GameTickCount();
+ int skip = 1;
+ MRect boardRect;
+
+ if( gameTime < loseTime )
+ return;
+
+ if( gameTime > loseTime )
+ {
+ skip = 2;
+ }
+
+ loseTime += skip;
+ loseStage += skip;
+
+ if( loseStage < 120 )
+ {
+ DropLosers( player, skip );
+ }
+ else if( loseStage == 120 || loseStage == 121 )
+ {
+ loseStage = 122;
+
+ boardRect.top = boardRect.left = 0;
+ boardRect.bottom = playerSurface[player]->h;
+ boardRect.bottom = playerSurface[player]->w;
+
+ SDLU_AcquireSurface( playerSurface[player] );
+ SurfaceDrawBoard( player, &boardRect );
+ SDLU_ReleaseSurface( playerSurface[player] );
+
+ CleanSpriteArea( player, &boardRect );
+ }
+ else if( loseStage == 240 || loseStage == 241 )
+ {
+ loseStage = 242;
+ if( players == 1 && control[player] == kPlayerControl )
+ {
+ if( --credits > 0 )
+ {
+ HandleDialog( kContinueDialog );
+ }
+ else
+ {
+ AddHiscore( score[player] );
+ ShowGameOverScreen( );
+
+ showStartMenu = true;
+ }
+ }
+ else if( players == 2 )
+ {
+ AddHiscore( score[player] );
+ }
+ }
+}
+
+void DropLosers( int player, int skip )
+{
+ int x, y, suck;
+ int beginDrop[] = { 28, 14, 0, 7, 21, 35 };
+ float thisDrop;
+ MRect myRect;
+
+ SDLU_AcquireSurface( playerSpriteSurface[player] );
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ if( loseStage >= beginDrop[x] )
+ {
+ thisDrop = last[x] + ( (float)(skip) * ( 0.7f + last[x] / 12.0f ) );
+
+ CalcBlobRect( x, 0, &myRect );
+ myRect.top = (int) last[x];
+ myRect.bottom = kGridDown * kBlobVertSize;
+ SurfaceDrawBoard( player, &myRect );
+ SetUpdateRect( player, &myRect );
+
+ if( thisDrop < (kGridDown*kBlobVertSize) )
+ {
+ myRect.top = (int) thisDrop;
+ myRect.bottom = myRect.top + kBlobVertSize;
+
+ y=0;
+ while( myRect.top < (kGridDown*kBlobVertSize) )
+ {
+ if( grid[player][x][y] >= kFirstBlob &&
+ grid[player][x][y] <= kLastBlob )
+ {
+ suck = suction[player][x][y] & (kUpDown);
+ if( suck == kNoSuction ) suck = kDying;
+ SurfaceDrawBlob( player, &myRect, grid[player][x][y], suck, charred[player][x][y] );
+ }
+ else if( grid[player][x][y] == kGray )
+ {
+ SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
+ }
+
+ OffsetMRect( &myRect, 0, kBlobVertSize );
+ y++;
+ }
+
+ last[x] = thisDrop;
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSpriteSurface[player] );
+}
+
+void Win( int player )
+{
+ int x, y;
+
+ if( GameTickCount() >= winTime )
+ {
+ if( winStage < (kGridDown * kGridAcross) )
+ {
+ y = (kGridDown-1) - (winStage / kGridAcross);
+ x = (winStage % kGridAcross);
+ if( y & 2 ) x = (kGridAcross-1) - x;
+
+ if( grid[player][x][y] == kGray )
+ {
+ suction[player][x][y] = kGrayBlink1;
+ death[player][x][y] = 0;
+ score[player] += 20;
+ }
+ else if( grid[player][x][y] >= kFirstBlob && grid[player][x][y] <= kLastBlob )
+ {
+ suction[player][x][y] = kInDeath;
+ death[player][x][y] = 0;
+ score[player] += 100;
+ }
+ }
+ else if( winStage == 140 && control[player] == kPlayerControl )
+ {
+ DrawTimerCount( player );
+ }
+ else if( winStage == 200 && control[player] == kPlayerControl )
+ {
+ DrawTimerBonus( player );
+ }
+
+ winTime++;
+ winStage++;
+ }
+
+ if( winStage < 140 )
+ {
+ KillBlobs( player );
+ }
+
+ if( winStage >= 280 )
+ {
+ if( control[player] == kPlayerControl )
+ {
+ IncrementLevel( );
+ BeginRound( true );
+ }
+ }
+}
+
+void DrawTimerCount( int player )
+{
+ MRect playerRect;
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ {
+ MPoint dPoint = { (kBlobVertSize * 3), 15 };
+
+ SurfaceBlitCharacter( victoryFont, 'A', &dPoint, 255, 255, 0, 1 );
+ }
+
+ {
+ MPoint dPoint = { (kBlobVertSize * 4), kBlobHorizSize };
+ char seconds[20];
+ char *scan = seconds;
+
+ sprintf( seconds, "%d", (endTime - startTime) / 60 );
+ while( *scan )
+ {
+ SurfaceBlitCharacter( zapFont, *scan++, &dPoint, 255, 255, 255, 1 );
+ dPoint.h--;
+ }
+
+ dPoint.h += 6;
+ SurfaceBlitCharacter( zapFont, 'S', &dPoint, 255, 255, 255, 1 );
+ }
+
+ playerRect.top = playerRect.left = 0;
+ playerRect.bottom = playerSurface[player]->h;
+ playerRect.right = playerSurface[player]->w;
+
+ CleanSpriteArea( player, &playerRect );
+ PlayStereo( player, kSplop );
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+}
+
+void DrawTimerBonus( int player )
+{
+ MRect playerRect;
+ int timer, bonus;
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ {
+ MPoint dPoint = { (kBlobVertSize * 6), 15 };
+
+ SurfaceBlitCharacter( victoryFont, 'B', &dPoint, 255, 255, 0, 1 );
+ }
+
+ timer = (endTime - startTime) / 60;
+ if( timer <= 10 ) bonus = 30000;
+ else if( timer <= 20 ) bonus = 10000;
+ else if( timer <= 30 ) bonus = 5000;
+ else if( timer <= 45 ) bonus = 4000;
+ else if( timer <= 60 ) bonus = 3000;
+ else if( timer <= 80 ) bonus = 2000;
+ else if( timer <=100 ) bonus = 1000;
+ else if( timer <=120 ) bonus = 500;
+ else bonus = 0;
+
+ if( players == 1 ) bonus *= level;
+
+ score[player] += bonus;
+
+ {
+ MPoint dPoint = { (kBlobVertSize * 7), kBlobHorizSize };
+ char points[20];
+ char *scan = points;
+
+ sprintf( points, "%d", bonus );
+ while( *scan )
+ {
+ SurfaceBlitCharacter( zapFont, *scan++, &dPoint, 255, 255, 255, 1 );
+ dPoint.h--;
+ }
+
+ dPoint.h += 6;
+ SurfaceBlitCharacter( zapFont, 'P', &dPoint, 255, 255, 255, 1 );
+ }
+
+ playerRect.top = playerRect.left = 0;
+ playerRect.bottom = playerSurface[player]->h;
+ playerRect.right = playerSurface[player]->w;
+
+ CleanSpriteArea( player, &playerRect );
+ PlayStereo( player, kSplop );
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+}
--- a/src/victory.cpp
+++ /dev/null
@@ -1,344 +1,0 @@
-// victory.c
-
-#include "SDLU.h"
-
-#include "main.h"
-#include "victory.h"
-#include "players.h"
-#include "gworld.h"
-#include "grays.h"
-#include "graphics.h"
-#include "soundfx.h"
-#include "score.h"
-#include "control.h"
-#include "random.h"
-#include "tweak.h"
-#include "gameticks.h"
-#include "level.h"
-#include "blitter.h"
-#include "music.h"
-#include "hiscore.h"
-#include "keyselect.h"
-#include "zap.h"
-#include "pause.h"
-#include "font.h"
-#include <math.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-MTicks winTime, loseTime;
-int winStage, loseStage;
-float drop[kGridAcross], last[kGridAcross];
-SkittlesFontPtr victoryFont;
-
-void InitVictory( void )
-{
- victoryFont = GetFont( picVictoryFont );
-}
-
-void EndRound( int player )
-{
- int count;
-
- loseTime = GameTickCount( );
- loseStage = 0;
-
- role[player] = kLosing;
- emotions[player] = kEmotionPanic;
-
- for( count=0; count<kGridAcross; count++ )
- {
- last[count] = 0.1f;
- drop[count] = 0.4f + RandomBefore(1000)/20000;
- rowBounce[player][count] = 99;
- }
-
- if( player == 0 )
- {
- ChooseMusic( -1 );
- PlayMono( kLoss );
- }
-}
-
-void BeginVictory( int player )
-{
- int count;
-
- endTime = GameTickCount( );
- winTime = GameTickCount( );
- winStage = 0;
-
- role[player] = kWinning;
- emotions[player] = kEmotionHappy;
-
- EraseSpriteBlobs( player );
-
- for( count=0; count<kGridAcross; count++ )
- {
- rowBounce[player][count] = 99;
- }
-
- if( player == 0 )
- {
- ChooseMusic( -1 );
- PlayMono( kVictory );
- }
-}
-
-void Lose( int player )
-{
- MTicks gameTime = GameTickCount();
- int skip = 1;
- MRect boardRect;
-
- if( gameTime < loseTime )
- return;
-
- if( gameTime > loseTime )
- {
- skip = 2;
- }
-
- loseTime += skip;
- loseStage += skip;
-
- if( loseStage < 120 )
- {
- DropLosers( player, skip );
- }
- else if( loseStage == 120 || loseStage == 121 )
- {
- loseStage = 122;
-
- boardRect.top = boardRect.left = 0;
- boardRect.bottom = playerSurface[player]->h;
- boardRect.bottom = playerSurface[player]->w;
-
- SDLU_AcquireSurface( playerSurface[player] );
- SurfaceDrawBoard( player, &boardRect );
- SDLU_ReleaseSurface( playerSurface[player] );
-
- CleanSpriteArea( player, &boardRect );
- }
- else if( loseStage == 240 || loseStage == 241 )
- {
- loseStage = 242;
- if( players == 1 && control[player] == kPlayerControl )
- {
- if( --credits > 0 )
- {
- HandleDialog( kContinueDialog );
- }
- else
- {
- AddHiscore( score[player] );
- ShowGameOverScreen( );
-
- showStartMenu = true;
- }
- }
- else if( players == 2 )
- {
- AddHiscore( score[player] );
- }
- }
-}
-
-void DropLosers( int player, int skip )
-{
- int x, y, suck;
- int beginDrop[] = { 28, 14, 0, 7, 21, 35 };
- float thisDrop;
- MRect myRect;
-
- SDLU_AcquireSurface( playerSpriteSurface[player] );
-
- for( x=0; x<kGridAcross; x++ )
- {
- if( loseStage >= beginDrop[x] )
- {
- thisDrop = last[x] + ( (float)(skip) * ( 0.7f + last[x] / 12.0f ) );
-
- CalcBlobRect( x, 0, &myRect );
- myRect.top = (int) last[x];
- myRect.bottom = kGridDown * kBlobVertSize;
- SurfaceDrawBoard( player, &myRect );
- SetUpdateRect( player, &myRect );
-
- if( thisDrop < (kGridDown*kBlobVertSize) )
- {
- myRect.top = (int) thisDrop;
- myRect.bottom = myRect.top + kBlobVertSize;
-
- y=0;
- while( myRect.top < (kGridDown*kBlobVertSize) )
- {
- if( grid[player][x][y] >= kFirstBlob &&
- grid[player][x][y] <= kLastBlob )
- {
- suck = suction[player][x][y] & (kUpDown);
- if( suck == kNoSuction ) suck = kDying;
- SurfaceDrawBlob( player, &myRect, grid[player][x][y], suck, charred[player][x][y] );
- }
- else if( grid[player][x][y] == kGray )
- {
- SurfaceDrawAlpha( &myRect, kGray, kLight, kGrayNoBlink );
- }
-
- OffsetMRect( &myRect, 0, kBlobVertSize );
- y++;
- }
-
- last[x] = thisDrop;
- }
- }
- }
-
- SDLU_ReleaseSurface( playerSpriteSurface[player] );
-}
-
-void Win( int player )
-{
- int x, y;
-
- if( GameTickCount() >= winTime )
- {
- if( winStage < (kGridDown * kGridAcross) )
- {
- y = (kGridDown-1) - (winStage / kGridAcross);
- x = (winStage % kGridAcross);
- if( y & 2 ) x = (kGridAcross-1) - x;
-
- if( grid[player][x][y] == kGray )
- {
- suction[player][x][y] = kGrayBlink1;
- death[player][x][y] = 0;
- score[player] += 20;
- }
- else if( grid[player][x][y] >= kFirstBlob && grid[player][x][y] <= kLastBlob )
- {
- suction[player][x][y] = kInDeath;
- death[player][x][y] = 0;
- score[player] += 100;
- }
- }
- else if( winStage == 140 && control[player] == kPlayerControl )
- {
- DrawTimerCount( player );
- }
- else if( winStage == 200 && control[player] == kPlayerControl )
- {
- DrawTimerBonus( player );
- }
-
- winTime++;
- winStage++;
- }
-
- if( winStage < 140 )
- {
- KillBlobs( player );
- }
-
- if( winStage >= 280 )
- {
- if( control[player] == kPlayerControl )
- {
- IncrementLevel( );
- BeginRound( true );
- }
- }
-}
-
-void DrawTimerCount( int player )
-{
- MRect playerRect;
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- {
- MPoint dPoint = { (kBlobVertSize * 3), 15 };
-
- SurfaceBlitCharacter( victoryFont, 'A', &dPoint, 255, 255, 0, 1 );
- }
-
- {
- MPoint dPoint = { (kBlobVertSize * 4), kBlobHorizSize };
- char seconds[20];
- char *scan = seconds;
-
- sprintf( seconds, "%d", (endTime - startTime) / 60 );
- while( *scan )
- {
- SurfaceBlitCharacter( zapFont, *scan++, &dPoint, 255, 255, 255, 1 );
- dPoint.h--;
- }
-
- dPoint.h += 6;
- SurfaceBlitCharacter( zapFont, 'S', &dPoint, 255, 255, 255, 1 );
- }
-
- playerRect.top = playerRect.left = 0;
- playerRect.bottom = playerSurface[player]->h;
- playerRect.right = playerSurface[player]->w;
-
- CleanSpriteArea( player, &playerRect );
- PlayStereo( player, kSplop );
-
- SDLU_ReleaseSurface( playerSurface[player] );
-}
-
-void DrawTimerBonus( int player )
-{
- MRect playerRect;
- int timer, bonus;
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- {
- MPoint dPoint = { (kBlobVertSize * 6), 15 };
-
- SurfaceBlitCharacter( victoryFont, 'B', &dPoint, 255, 255, 0, 1 );
- }
-
- timer = (endTime - startTime) / 60;
- if( timer <= 10 ) bonus = 30000;
- else if( timer <= 20 ) bonus = 10000;
- else if( timer <= 30 ) bonus = 5000;
- else if( timer <= 45 ) bonus = 4000;
- else if( timer <= 60 ) bonus = 3000;
- else if( timer <= 80 ) bonus = 2000;
- else if( timer <=100 ) bonus = 1000;
- else if( timer <=120 ) bonus = 500;
- else bonus = 0;
-
- if( players == 1 ) bonus *= level;
-
- score[player] += bonus;
-
- {
- MPoint dPoint = { (kBlobVertSize * 7), kBlobHorizSize };
- char points[20];
- char *scan = points;
-
- sprintf( points, "%d", bonus );
- while( *scan )
- {
- SurfaceBlitCharacter( zapFont, *scan++, &dPoint, 255, 255, 255, 1 );
- dPoint.h--;
- }
-
- dPoint.h += 6;
- SurfaceBlitCharacter( zapFont, 'P', &dPoint, 255, 255, 255, 1 );
- }
-
- playerRect.top = playerRect.left = 0;
- playerRect.bottom = playerSurface[player]->h;
- playerRect.right = playerSurface[player]->w;
-
- CleanSpriteArea( player, &playerRect );
- PlayStereo( player, kSplop );
-
- SDLU_ReleaseSurface( playerSurface[player] );
-}
--- /dev/null
+++ b/src/zap.c
@@ -1,0 +1,639 @@
+// zap.cpp
+
+#include "SDLU.h"
+
+#include <stdio.h>
+
+#include "main.h"
+#include "players.h"
+#include "zap.h"
+#include "grays.h"
+#include "soundfx.h"
+#include "gworld.h"
+#include "graphics.h"
+#include "gameticks.h"
+#include "level.h"
+#include "random.h"
+#include "tweak.h"
+#include "blitter.h"
+#include "font.h"
+#include "score.h"
+#include "hiscore.h"
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+
+signed char death[2][kGridAcross][kGridDown];
+int zapIteration[2];
+int grenadeFrame[2] = {kBlastFrames + 1, kBlastFrames + 1}, zapScoreFrame[2];
+MPoint zapScorePt[2];
+MRect grenadeRect[2];
+SkittlesFontPtr zapFont, zapOutline;
+char zapScore[2][20] = { "", "" };
+int zapScoreWidth[2];
+int zapScoreR[2], zapScoreG[2], zapScoreB[2];
+int zapOffsetX[7][kZapFrames], zapOffsetY[7][kZapFrames];
+
+void ZapScoreDisplay( int player, int amount, int multiplier, int x, int y, int c )
+{
+ char *scan;
+
+ if( amount > 0 &&
+ multiplier > 0 &&
+ x >= 0 && x < kGridAcross &&
+ y >= 0 && y < kGridDown &&
+ c >= kFirstBlob && c <= (kLastBlob+1) )
+ {
+ zapScorePt[player].v = y * kBlobVertSize + 6;
+ zapScorePt[player].h = x * kBlobHorizSize + 6;
+
+ zapScoreR[player] = glowColors[c][0];
+ zapScoreG[player] = glowColors[c][1];
+ zapScoreB[player] = glowColors[c][2];
+
+ sprintf( zapScore[player], (multiplier == 1)? "%d": "%d*%d", amount, multiplier );
+
+ zapScoreWidth[player] = 0;
+ scan = zapScore[player];
+ while( *scan ) zapScoreWidth[player] += zapFont->width[(uint8_t) * scan++];
+
+ if( (zapScorePt[player].h + zapScoreWidth[player] + 8) > (kGridAcross * kBlobHorizSize) )
+ {
+ zapScorePt[player].h = (kGridAcross * kBlobHorizSize) - zapScoreWidth[player] - 8;
+ }
+ }
+}
+
+void ZapBlobs( int player )
+{
+ int x, y, cluster, clusterCount = 0, multiplier, amount = 0;
+ int zapFocusX = -1, zapFocusY = -1, zapFocusC = 0;
+
+
+ zapScorePt[player].v = 0;
+ zapScoreFrame[player] = 0;
+
+ switch( chain[player] )
+ {
+ case 1: multiplier = 1; break;
+ default: multiplier = 2 << chain[player]; break;
+ }
+
+ for( y=kGridDown-1; y>=0; y-- )
+ {
+ for( x=kGridAcross-1; x>=0; x-- )
+ {
+ if( grid[player][x][y] >= kFirstBlob &&
+ grid[player][x][y] <= kLastBlob &&
+ suction[player][x][y] != kInDeath )
+ {
+ cluster = SizeUp( grid[player], x, y, grid[player][x][y] );
+ if( cluster >= kBlobClusterSize )
+ {
+ clusterCount++;
+ zapFocusX = x;
+ zapFocusY = y;
+ zapFocusC = grid[player][x][y];
+
+ amount += cluster * 10;
+
+ multiplier += cluster - kBlobClusterSize;
+
+ RemoveBlobs( player, x, y, grid[player][x][y], 0 );
+ }
+ }
+ }
+ }
+
+ if( clusterCount > 0 )
+ {
+ switch( clusterCount )
+ {
+ case 1: break;
+ case 2: multiplier += 3; break;
+ case 3: multiplier += 6; break;
+ case 4: multiplier += 12; break;
+ default: multiplier += 24; break;
+ }
+
+ if( multiplier > 999 ) multiplier = 999;
+ CalculateGrays( 1-player, amount * multiplier / difficulty[player] );
+ potentialCombo[player].value += amount * multiplier;
+
+ if( players == 1 ) amount *= ((level <= kLevels)? level: 1);
+ score[player] += amount * multiplier;
+
+ ZapScoreDisplay( player, amount, multiplier, zapFocusX, zapFocusY, zapFocusC );
+ }
+
+ blobTime[player] = GameTickCount( );
+
+ if( clusterCount > 0 )
+ {
+ chain[player]++;
+ role[player] = kKillBlobs;
+ PlayStereoFrequency( player, kSquishy, zapIteration[player]++ );
+ }
+ else
+ {
+ if( control[player] == kPlayerControl )
+ {
+ SubmitCombo( &potentialCombo[player] );
+ }
+
+ SetupGrays( player );
+ role[player] = kDropGrays;
+
+ if( BusyDroppingGrays( player ) )
+ {
+ PlayStereoFrequency( player, kWhistle, player );
+ }
+ }
+}
+
+void RemoveBlobs( int player, int x, int y, int color, int generation )
+{
+ if( (x<0) || (x>=kGridAcross) || (y<0) || (y>=kGridDown) )
+ return;
+
+ if( grid[player][x][y] == kGray )
+ {
+ suction[player][x][y] = kGrayBlink1;
+ death[player][x][y] = -8 - generation;
+ return;
+ }
+
+ if( grid[player][x][y] != color || suction[player][x][y] == kInDeath )
+ return;
+
+ suction[player][x][y] = kInDeath;
+ death[player][x][y] = -12 - generation;
+
+ RemoveBlobs( player, x-1, y, color, generation+3 );
+ RemoveBlobs( player, x+1, y, color, generation+3 );
+ RemoveBlobs( player, x, y-1, color, generation+3 );
+ RemoveBlobs( player, x, y+1, color, generation+3 );
+}
+
+void KillBlobs( int player )
+{
+ int x,y;
+ const int position[] = { 0, 15, 27, 39, 51, 63, 72, 81, 90, 99, 105,111,117,123,126,129,131,132,133,134,135,135,136,136,137,137,138,138,138,139,139,139,139,140,140,140 };
+ const int shading [] =
+ {
+ _5TO8(20),
+ _5TO8(21),
+ _5TO8(22),
+ _5TO8(23),
+ _5TO8(24),
+ _5TO8(25),
+ _5TO8(26),
+ _5TO8(27),
+ _5TO8(28),
+ _5TO8(29),
+ _5TO8(30),
+ _5TO8(31),
+ _5TO8(31),
+ _5TO8(31),
+ _5TO8(31),
+ _5TO8(31),
+ _5TO8(31),
+ _5TO8(31),
+ _5TO8(31),
+ _5TO8(31),
+ _5TO8(31),
+ _5TO8(31),
+ _5TO8(31),
+ _5TO8(30),
+ _5TO8(29),
+ _5TO8(28),
+ _5TO8(26),
+ _5TO8(24),
+ _5TO8(21),
+ _5TO8(18),
+ _5TO8(15),
+ _5TO8(12),
+ _5TO8(9),
+ _5TO8(6),
+ _5TO8(3),
+ _5TO8(0)
+ };
+ const int blobGraphic[kZapFrames] = { kDying, kDying, kDying, kDying, kSquish1,
+ kSquish1, kSquish1, kSquish1, kSquish2, kSquish2,
+ kSquish2, kSquish2, kSquish3, kSquish3, kSquish3,
+ kSquish3, kSquish4, kSquish4, kSquish4, kSquish4 },
+ grayGraphic[kZapFrames] = { kGrayBlink1, kGrayBlink1, kGrayBlink1,
+ kGrayBlink1, kGrayBlink1, kGrayBlink1,
+ kGrayBlink2, kGrayBlink2, kGrayBlink2,
+ kGrayBlink2, kGrayBlink2, kGrayBlink2,
+ kGrayBlink3, kGrayBlink3, kGrayBlink3,
+ kGrayBlink3, kGrayBlink3, kGrayBlink3,
+ kGrayBlink3, kGrayBlink3 };
+ MRect myRect;
+ MBoolean busy = false;
+ MPoint dPoint, oPoint;
+ char *scan;
+
+ if( blobTime[player] > GameTickCount( ) )
+ return;
+
+ blobTime[player]++;
+
+ SDLU_AcquireSurface( playerSurface[player] );
+
+ // clear grenade sprite
+ if( grenadeFrame[player] <= kBlastFrames )
+ {
+ CleanSpriteArea( player, &grenadeRect[player] );
+ if( grenadeFrame[player] == kBlastFrames ) grenadeFrame[player]++;
+ }
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ if( grid[player][x][y] >= kFirstBlob && // if a blob is dying
+ grid[player][x][y] <= kLastBlob &&
+ suction[player][x][y] == kInDeath )
+ {
+ death[player][x][y]++;
+ busy = true;
+
+ CalcBlobRect( x, y, &myRect );
+
+ if( death[player][x][y] >= 0 && death[player][x][y] <= kZapFrames ) // draw its death
+ {
+ if( death[player][x][y] == kZapFrames )
+ {
+ grid[player][x][y] = kEmpty;
+ suction[player][x][y] = kNoSuction;
+ charred[player][x][y] = kNoCharring;
+ SurfaceDrawBlob( player, &myRect, kEmpty, kNoSuction, kNoCharring );
+ CleanSpriteArea( player, &myRect );
+ }
+ else
+ {
+ SurfaceDrawBlob( player, &myRect,
+ grid[player][x][y],
+ blobGraphic[ death[player][x][y] ],
+ kNoCharring );
+ CleanSpriteArea( player, &myRect );
+ }
+
+ CleanChunks( player, x, y, death[player][x][y], character[player].zapStyle );
+ }
+ else
+ {
+ SurfaceDrawBlob( player, &myRect, grid[player][x][y],
+ (blobTime[player] & 2)? kFlashDarkBlob: kNoSuction, kNoCharring );
+ CleanSpriteArea( player, &myRect );
+ }
+ }
+ else
+ {
+ if( grid[player][x][y] == kGray && // gray dying
+ suction[player][x][y] == kGrayBlink1 )
+ {
+ CalcBlobRect( x, y, &myRect );
+
+ if( death[player][x][y] >= 0 && death[player][x][y] <= kZapFrames )
+ {
+ if( death[player][x][y] == kZapFrames )
+ {
+ grid[player][x][y] = kEmpty;
+ suction[player][x][y] = kNoSuction;
+ SurfaceDrawBlob( player, &myRect, kEmpty, kNoSuction, kNoCharring );
+ }
+ else
+ {
+ SurfaceDrawBoard( player, &myRect );
+ SurfaceDrawAlpha( &myRect, kGray, kLight, grayGraphic[ death[player][x][y] ] );
+ busy = true;
+ }
+ CleanSpriteArea( player, &myRect );
+ }
+
+ death[player][x][y]++;
+ }
+ }
+ }
+ }
+
+ // draw score info above blobs but below chunks and explosions
+
+ if( zapScoreFrame[player] < arrsize(position) )
+ {
+ myRect.top = zapScorePt[player].v - (position[zapScoreFrame[player] ]);
+ myRect.left = zapScorePt[player].h;
+ myRect.bottom = zapScorePt[player].v - (position[zapScoreFrame[player] - 1]) + 15;
+ myRect.right = myRect.left + zapScoreWidth[player];
+ CleanSpriteArea( player, &myRect );
+
+ if( zapScoreFrame[player] < arrsize(position)-1 )
+ {
+ SDLU_AcquireSurface( playerSpriteSurface[player] );
+
+ dPoint.v = oPoint.v = myRect.top;
+ dPoint.h = oPoint.h = myRect.left;
+ scan = zapScore[player];
+ while( *scan )
+ {
+ SurfaceBlitWeightedCharacter( zapFont, *scan, &dPoint, zapScoreR[player], zapScoreG[player], zapScoreB[player], shading[zapScoreFrame[player]] );
+ SurfaceBlitWeightedCharacter( zapOutline, *scan, &oPoint, 0, 0, 0, shading[zapScoreFrame[player]] );
+ scan++;
+ }
+
+ SDLU_ReleaseSurface( playerSpriteSurface[player] );
+
+ zapScoreFrame[player]++;
+ busy = true;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////
+
+ for( x=0; x<kGridAcross; x++ )
+ {
+ for( y=0; y<kGridDown; y++ )
+ {
+ if( grid[player][x][y] >= kFirstBlob && // if a blob is dying
+ grid[player][x][y] <= kLastBlob &&
+ suction[player][x][y] == kInDeath &&
+ death[player][x][y] >= 0 && death[player][x][y] < kZapFrames ) // draw chunks (after all that stuff)
+ {
+ DrawChunks( player, x, y, death[player][x][y], character[player].zapStyle );
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSurface[player] );
+
+ if( grenadeFrame[player] < kBlastFrames )
+ {
+ busy = true;
+
+ SDLU_AcquireSurface( playerSpriteSurface[player] );
+
+ myRect.top = grenadeFrame[player] * kBlastHeight;
+ myRect.left = 0;
+ myRect.bottom = myRect.top + kBlastHeight;
+ myRect.right = kBlastWidth;
+
+ SurfaceBlitAlpha( playerSpriteSurface[player], blastSurface, blastMaskSurface, playerSpriteSurface[player],
+ &grenadeRect[player], &myRect, &myRect, &grenadeRect[player] );
+
+ grenadeFrame[player]++;
+
+ SDLU_ReleaseSurface( playerSpriteSurface[player] );
+ }
+
+ if( !busy && role[player] == kKillBlobs )
+ {
+ blobTime[player] = GameTickCount( );
+ halfway[player] = false;
+ role[player] = kDropBlobs;
+ }
+}
+
+int SizeUp( signed char myGrid[kGridAcross][kGridDown], int x, int y, int color )
+{
+ int total;
+
+ total = GetChainSize( myGrid, x, y, color );
+ CleanSize( myGrid, x, y, color );
+
+ return total;
+}
+
+int GetChainSize( signed char myGrid[kGridAcross][kGridDown], int x, int y, int color )
+{
+ int total;
+
+ if( (x<0) || (x>=kGridAcross) || (y<0) || (y>=kGridDown) ) return 0;
+ if( myGrid[x][y] != color ) return 0;
+
+ myGrid[x][y] = -color;
+
+ total = 1 + GetChainSize( myGrid, x-1, y, color )
+ + GetChainSize( myGrid, x+1, y, color )
+ + GetChainSize( myGrid, x, y-1, color )
+ + GetChainSize( myGrid, x, y+1, color );
+
+ return total;
+}
+
+void CleanWithPolish( signed char myGrid[kGridAcross][kGridDown], signed char polish[kGridAcross][kGridDown], int x, int y, int color )
+{
+ if( (x<0) || (x>=kGridAcross) || (y<0) || (y>=kGridDown) ) return;
+
+ if( myGrid[x][y] == -color )
+ {
+ myGrid[x][y] = color;
+ polish[x][y] = true;
+
+ CleanWithPolish( myGrid, polish, x-1, y, color );
+ CleanWithPolish( myGrid, polish, x+1, y, color );
+ CleanWithPolish( myGrid, polish, x, y-1, color );
+ CleanWithPolish( myGrid, polish, x, y+1, color );
+ }
+}
+
+void CleanSize( signed char myGrid[kGridAcross][kGridDown], int x, int y, int color )
+{
+ if( (x<0) || (x>=kGridAcross) || (y<0) || (y>=kGridDown) ) return;
+
+ if( myGrid[x][y] == -color )
+ {
+ myGrid[x][y] = color;
+
+ CleanSize( myGrid, x-1, y, color );
+ CleanSize( myGrid, x+1, y, color );
+ CleanSize( myGrid, x, y-1, color );
+ CleanSize( myGrid, x, y+1, color );
+ }
+}
+
+void CleanChunks( int player, int x, int y, int level, int style )
+{
+ int count, color, type;
+ MRect chunkRect;
+
+ SDLU_AcquireSurface( playerSpriteSurface[player] );
+
+ for( count=-3; count<=3; count++ )
+ {
+ if( count != 0 )
+ {
+ if( level > 0 )
+ {
+ CalcBlobRect( x, y, &chunkRect );
+ GetZapStyle( player, &chunkRect, &color, &type, count, level-1, style );
+ CleanSpriteArea( player, &chunkRect );
+ }
+
+ if( level < kZapFrames )
+ {
+ CalcBlobRect( x, y, &chunkRect );
+ GetZapStyle( player, &chunkRect, &color, &type, count, level, style );
+ CleanSpriteArea( player, &chunkRect );
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSpriteSurface[player] );
+}
+
+void DrawChunks( int player, int x, int y, int level, int style )
+{
+ int count, color, type;
+ MRect chunkRect;
+
+ SDLU_AcquireSurface( playerSpriteSurface[player] );
+
+ for( count=-3; count<=3; count++ )
+ {
+ if( count != 0 )
+ {
+ CalcBlobRect( x, y, &chunkRect );
+ color = grid[player][x][y];
+ GetZapStyle( player, &chunkRect, &color, &type, count, level, style );
+ SurfaceDrawSprite( &chunkRect, color, type );
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSpriteSurface[player] );
+}
+
+void CleanSplat( int player, int x, int y, int level )
+{
+ int count, color, type;
+ MRect chunkRect;
+
+ SDLU_AcquireSurface( playerSpriteSurface[player] );
+
+ for( count=-2; count<=2; count++ )
+ {
+ if( count != 0 )
+ {
+ if( level > 0 )
+ {
+ CalcBlobRect( x, y, &chunkRect );
+ GetZapStyle( player, &chunkRect, &color, &type, count, level-1, 4 );
+ CleanSpriteArea( player, &chunkRect );
+ }
+
+ if( level < kZapFrames )
+ {
+ CalcBlobRect( x, y, &chunkRect );
+ GetZapStyle( player, &chunkRect, &color, &type, count, level, 4 );
+ CleanSpriteArea( player, &chunkRect );
+ }
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSpriteSurface[player] );
+}
+
+void DrawSplat( int player, int x, int y, int level )
+{
+ int count, color = kGray, type;
+ MRect chunkRect;
+
+ SDLU_AcquireSurface( playerSpriteSurface[player] );
+
+ for( count=-2; count<=2; count++ )
+ {
+ if( level < kZapFrames && count != 0 )
+ {
+ CalcBlobRect( x, y, &chunkRect );
+ GetZapStyle( player, &chunkRect, &color, &type, count, level, 4 );
+ SurfaceDrawAlpha( &chunkRect, kGray, kLight, type );
+ }
+ }
+
+ SDLU_ReleaseSurface( playerSpriteSurface[player] );
+}
+
+void InitZapStyle( void )
+{
+ int count, which;
+ double x;
+ const double position[kZapFrames] = {0, 10, 20, 28, 35, 42, 48, 54, 60, 64, 68, 70, 72, 73, 73, 74, 74, 75, 75, 75};
+ const double offset[7] = {-30, -50, -70, 0, -110, -130, -150};
+
+ zapFont = GetFont( picZapFont );
+ zapOutline = GetFont( picZapOutlineFont );
+
+ for( count=0; count<kZapFrames; count++ )
+ {
+ for( which=0; which<7; which++ )
+ {
+ x = d2r(offset[which]);
+
+ zapOffsetX[which][count] = (int) floor( 0.5 + position[count] * cos( x ) );
+ zapOffsetY[which][count] = (int) floor( 0.5 + position[count] * sin( x ) );
+ }
+ }
+}
+
+
+void GetZapStyle( int player, MRect *myRect, int *color, int *type, int which, int level, int style )
+{
+ const int chunkGraphic[] = { kSquish1, kSquish1, kSquish1, kSquish1, kSquish1,
+ kSquish2, kSquish2, kSquish2, kSquish2, kSquish2,
+ kSquish3, kSquish3, kSquish3, kSquish3, kSquish3,
+ kSquish4, kSquish4, kSquish4, kSquish4, kSquish4 };
+
+ (void) color; // later
+ *type = chunkGraphic[level];
+
+ switch( style )
+ {
+ case 0:
+ {
+ const int direction[7][2] = { {0, -2}, {-2,-1}, {-2,1}, {0,0}, {2,-1}, {2,1}, {0, 2} };
+ const int position[kZapFrames] = {0, 5, 9, 13, 17, 21, 24, 26, 30, 33, 35, 37, 39, 41, 42, 43, 43, 44, 44, 44 };
+
+ OffsetMRect( myRect, direction[which+3][0] * position[level],
+ direction[which+3][1] * position[level] );
+ break;
+ }
+
+
+ case 1:
+ {
+ const int xVelocity = 3;
+ const int yOffset[3][kZapFrames] = { { -4, -8, -12, -17, -22, -26, -30, -33, -36, -39, -41, -42, -43, -44, -44, -44, -43, -42, -41, -39 },
+ { -4, -7, -10, -14, -18, -21, -23, -25, -26, -27, -27, -27, -26, -25, -23, -21, -18, -14, -10, -7 },
+ { -2, -4, -5, -6, -7, -8, -9, -10, -10, -11, -11, -11, -10, -9, -8, -7, -6, -5, -3, -1 } };
+
+ OffsetMRect( myRect, xVelocity * level * which, yOffset[abs(which)-1][level] );
+
+ break;
+ }
+
+ case 2:
+ {
+ const int position[kZapFrames] = {0, 5, 9, 13, 17, 21, 24, 27, 30, 33, 35, 37, 39, 41, 42, 43, 43, 44, 44, 44 };
+
+ OffsetMRect( myRect, 0, position[level] * which );
+ break;
+ }
+
+ case 3:
+ {
+ double fLevel = ((double)level) / 2;
+ OffsetMRect( myRect, (int)((player? -1.0: 1.0) * abs(which) * fLevel * (fLevel-1)), (int)((which-3) * fLevel) );
+ break;
+ }
+
+ case 4:
+ {
+ OffsetMRect( myRect, zapOffsetX[which+3][level],
+ zapOffsetY[which+3][level] );
+
+ break;
+ }
+ }
+}
--- a/src/zap.cpp
+++ /dev/null
@@ -1,642 +1,0 @@
-// zap.cpp
-
-#include "SDLU.h"
-
-#include <stdio.h>
-#include <algorithm>
-
-#include "main.h"
-#include "players.h"
-#include "zap.h"
-#include "grays.h"
-#include "soundfx.h"
-#include "gworld.h"
-#include "graphics.h"
-#include "gameticks.h"
-#include "level.h"
-#include "random.h"
-#include "tweak.h"
-#include "blitter.h"
-#include "font.h"
-#include "score.h"
-#include "hiscore.h"
-
-#include <stdlib.h>
-#include <math.h>
-#include <stdio.h>
-
-signed char death[2][kGridAcross][kGridDown];
-int zapIteration[2];
-int grenadeFrame[2] = {kBlastFrames + 1, kBlastFrames + 1}, zapScoreFrame[2];
-MPoint zapScorePt[2];
-MRect grenadeRect[2];
-SkittlesFontPtr zapFont, zapOutline;
-char zapScore[2][20] = { "", "" };
-int zapScoreWidth[2];
-int zapScoreR[2], zapScoreG[2], zapScoreB[2];
-int zapOffsetX[7][kZapFrames], zapOffsetY[7][kZapFrames];
-
-using std::min;
-
-void ZapScoreDisplay( int player, int amount, int multiplier, int x, int y, int c )
-{
- char *scan;
-
- if( amount > 0 &&
- multiplier > 0 &&
- x >= 0 && x < kGridAcross &&
- y >= 0 && y < kGridDown &&
- c >= kFirstBlob && c <= (kLastBlob+1) )
- {
- zapScorePt[player].v = y * kBlobVertSize + 6;
- zapScorePt[player].h = x * kBlobHorizSize + 6;
-
- zapScoreR[player] = glowColors[c][0];
- zapScoreG[player] = glowColors[c][1];
- zapScoreB[player] = glowColors[c][2];
-
- sprintf( zapScore[player], (multiplier == 1)? "%d": "%d*%d", amount, multiplier );
-
- zapScoreWidth[player] = 0;
- scan = zapScore[player];
- while( *scan ) zapScoreWidth[player] += zapFont->width[(uint8_t) * scan++];
-
- if( (zapScorePt[player].h + zapScoreWidth[player] + 8) > (kGridAcross * kBlobHorizSize) )
- {
- zapScorePt[player].h = (kGridAcross * kBlobHorizSize) - zapScoreWidth[player] - 8;
- }
- }
-}
-
-void ZapBlobs( int player )
-{
- int x, y, cluster, clusterCount = 0, multiplier, amount = 0;
- int zapFocusX = -1, zapFocusY = -1, zapFocusC = 0;
-
-
- zapScorePt[player].v = 0;
- zapScoreFrame[player] = 0;
-
- switch( chain[player] )
- {
- case 1: multiplier = 1; break;
- default: multiplier = 2 << chain[player]; break;
- }
-
- for( y=kGridDown-1; y>=0; y-- )
- {
- for( x=kGridAcross-1; x>=0; x-- )
- {
- if( grid[player][x][y] >= kFirstBlob &&
- grid[player][x][y] <= kLastBlob &&
- suction[player][x][y] != kInDeath )
- {
- cluster = SizeUp( grid[player], x, y, grid[player][x][y] );
- if( cluster >= kBlobClusterSize )
- {
- clusterCount++;
- zapFocusX = x;
- zapFocusY = y;
- zapFocusC = grid[player][x][y];
-
- amount += cluster * 10;
-
- multiplier += cluster - kBlobClusterSize;
-
- RemoveBlobs( player, x, y, grid[player][x][y], 0 );
- }
- }
- }
- }
-
- if( clusterCount > 0 )
- {
- switch( clusterCount )
- {
- case 1: break;
- case 2: multiplier += 3; break;
- case 3: multiplier += 6; break;
- case 4: multiplier += 12; break;
- default: multiplier += 24; break;
- }
-
- if( multiplier > 999 ) multiplier = 999;
- CalculateGrays( 1-player, amount * multiplier / difficulty[player] );
- potentialCombo[player].value += amount * multiplier;
-
- if( players == 1 ) amount *= ((level <= kLevels)? level: 1);
- score[player] += amount * multiplier;
-
- ZapScoreDisplay( player, amount, multiplier, zapFocusX, zapFocusY, zapFocusC );
- }
-
- blobTime[player] = GameTickCount( );
-
- if( clusterCount > 0 )
- {
- chain[player]++;
- role[player] = kKillBlobs;
- PlayStereoFrequency( player, kSquishy, zapIteration[player]++ );
- }
- else
- {
- if( control[player] == kPlayerControl )
- {
- SubmitCombo( &potentialCombo[player] );
- }
-
- SetupGrays( player );
- role[player] = kDropGrays;
-
- if( BusyDroppingGrays( player ) )
- {
- PlayStereoFrequency( player, kWhistle, player );
- }
- }
-}
-
-void RemoveBlobs( int player, int x, int y, int color, int generation )
-{
- if( (x<0) || (x>=kGridAcross) || (y<0) || (y>=kGridDown) )
- return;
-
- if( grid[player][x][y] == kGray )
- {
- suction[player][x][y] = kGrayBlink1;
- death[player][x][y] = -8 - generation;
- return;
- }
-
- if( grid[player][x][y] != color || suction[player][x][y] == kInDeath )
- return;
-
- suction[player][x][y] = kInDeath;
- death[player][x][y] = -12 - generation;
-
- RemoveBlobs( player, x-1, y, color, generation+3 );
- RemoveBlobs( player, x+1, y, color, generation+3 );
- RemoveBlobs( player, x, y-1, color, generation+3 );
- RemoveBlobs( player, x, y+1, color, generation+3 );
-}
-
-void KillBlobs( int player )
-{
- int x,y;
- const int position[] = { 0, 15, 27, 39, 51, 63, 72, 81, 90, 99, 105,111,117,123,126,129,131,132,133,134,135,135,136,136,137,137,138,138,138,139,139,139,139,140,140,140 };
- const int shading [] =
- {
- _5TO8(20),
- _5TO8(21),
- _5TO8(22),
- _5TO8(23),
- _5TO8(24),
- _5TO8(25),
- _5TO8(26),
- _5TO8(27),
- _5TO8(28),
- _5TO8(29),
- _5TO8(30),
- _5TO8(31),
- _5TO8(31),
- _5TO8(31),
- _5TO8(31),
- _5TO8(31),
- _5TO8(31),
- _5TO8(31),
- _5TO8(31),
- _5TO8(31),
- _5TO8(31),
- _5TO8(31),
- _5TO8(31),
- _5TO8(30),
- _5TO8(29),
- _5TO8(28),
- _5TO8(26),
- _5TO8(24),
- _5TO8(21),
- _5TO8(18),
- _5TO8(15),
- _5TO8(12),
- _5TO8(9),
- _5TO8(6),
- _5TO8(3),
- _5TO8(0)
- };
- const int blobGraphic[kZapFrames] = { kDying, kDying, kDying, kDying, kSquish1,
- kSquish1, kSquish1, kSquish1, kSquish2, kSquish2,
- kSquish2, kSquish2, kSquish3, kSquish3, kSquish3,
- kSquish3, kSquish4, kSquish4, kSquish4, kSquish4 },
- grayGraphic[kZapFrames] = { kGrayBlink1, kGrayBlink1, kGrayBlink1,
- kGrayBlink1, kGrayBlink1, kGrayBlink1,
- kGrayBlink2, kGrayBlink2, kGrayBlink2,
- kGrayBlink2, kGrayBlink2, kGrayBlink2,
- kGrayBlink3, kGrayBlink3, kGrayBlink3,
- kGrayBlink3, kGrayBlink3, kGrayBlink3,
- kGrayBlink3, kGrayBlink3 };
- MRect myRect;
- MBoolean busy = false;
- MPoint dPoint, oPoint;
- char *scan;
-
- if( blobTime[player] > GameTickCount( ) )
- return;
-
- blobTime[player]++;
-
- SDLU_AcquireSurface( playerSurface[player] );
-
- // clear grenade sprite
- if( grenadeFrame[player] <= kBlastFrames )
- {
- CleanSpriteArea( player, &grenadeRect[player] );
- if( grenadeFrame[player] == kBlastFrames ) grenadeFrame[player]++;
- }
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- if( grid[player][x][y] >= kFirstBlob && // if a blob is dying
- grid[player][x][y] <= kLastBlob &&
- suction[player][x][y] == kInDeath )
- {
- death[player][x][y]++;
- busy = true;
-
- CalcBlobRect( x, y, &myRect );
-
- if( death[player][x][y] >= 0 && death[player][x][y] <= kZapFrames ) // draw its death
- {
- if( death[player][x][y] == kZapFrames )
- {
- grid[player][x][y] = kEmpty;
- suction[player][x][y] = kNoSuction;
- charred[player][x][y] = kNoCharring;
- SurfaceDrawBlob( player, &myRect, kEmpty, kNoSuction, kNoCharring );
- CleanSpriteArea( player, &myRect );
- }
- else
- {
- SurfaceDrawBlob( player, &myRect,
- grid[player][x][y],
- blobGraphic[ death[player][x][y] ],
- kNoCharring );
- CleanSpriteArea( player, &myRect );
- }
-
- CleanChunks( player, x, y, death[player][x][y], character[player].zapStyle );
- }
- else
- {
- SurfaceDrawBlob( player, &myRect, grid[player][x][y],
- (blobTime[player] & 2)? kFlashDarkBlob: kNoSuction, kNoCharring );
- CleanSpriteArea( player, &myRect );
- }
- }
- else
- {
- if( grid[player][x][y] == kGray && // gray dying
- suction[player][x][y] == kGrayBlink1 )
- {
- CalcBlobRect( x, y, &myRect );
-
- if( death[player][x][y] >= 0 && death[player][x][y] <= kZapFrames )
- {
- if( death[player][x][y] == kZapFrames )
- {
- grid[player][x][y] = kEmpty;
- suction[player][x][y] = kNoSuction;
- SurfaceDrawBlob( player, &myRect, kEmpty, kNoSuction, kNoCharring );
- }
- else
- {
- SurfaceDrawBoard( player, &myRect );
- SurfaceDrawAlpha( &myRect, kGray, kLight, grayGraphic[ death[player][x][y] ] );
- busy = true;
- }
- CleanSpriteArea( player, &myRect );
- }
-
- death[player][x][y]++;
- }
- }
- }
- }
-
- // draw score info above blobs but below chunks and explosions
-
- if( zapScoreFrame[player] < arrsize(position) )
- {
- myRect.top = zapScorePt[player].v - (position[zapScoreFrame[player] ]);
- myRect.left = zapScorePt[player].h;
- myRect.bottom = zapScorePt[player].v - (position[zapScoreFrame[player] - 1]) + 15;
- myRect.right = myRect.left + zapScoreWidth[player];
- CleanSpriteArea( player, &myRect );
-
- if( zapScoreFrame[player] < arrsize(position)-1 )
- {
- SDLU_AcquireSurface( playerSpriteSurface[player] );
-
- dPoint.v = oPoint.v = myRect.top;
- dPoint.h = oPoint.h = myRect.left;
- scan = zapScore[player];
- while( *scan )
- {
- SurfaceBlitWeightedCharacter( zapFont, *scan, &dPoint, zapScoreR[player], zapScoreG[player], zapScoreB[player], shading[zapScoreFrame[player]] );
- SurfaceBlitWeightedCharacter( zapOutline, *scan, &oPoint, 0, 0, 0, shading[zapScoreFrame[player]] );
- scan++;
- }
-
- SDLU_ReleaseSurface( playerSpriteSurface[player] );
-
- zapScoreFrame[player]++;
- busy = true;
- }
- }
-
- ///////////////////////////////////////////////////////////////
-
- for( x=0; x<kGridAcross; x++ )
- {
- for( y=0; y<kGridDown; y++ )
- {
- if( grid[player][x][y] >= kFirstBlob && // if a blob is dying
- grid[player][x][y] <= kLastBlob &&
- suction[player][x][y] == kInDeath &&
- death[player][x][y] >= 0 && death[player][x][y] < kZapFrames ) // draw chunks (after all that stuff)
- {
- DrawChunks( player, x, y, death[player][x][y], character[player].zapStyle );
- }
- }
- }
-
- SDLU_ReleaseSurface( playerSurface[player] );
-
- if( grenadeFrame[player] < kBlastFrames )
- {
- busy = true;
-
- SDLU_AcquireSurface( playerSpriteSurface[player] );
-
- myRect.top = grenadeFrame[player] * kBlastHeight;
- myRect.left = 0;
- myRect.bottom = myRect.top + kBlastHeight;
- myRect.right = kBlastWidth;
-
- SurfaceBlitAlpha( playerSpriteSurface[player], blastSurface, blastMaskSurface, playerSpriteSurface[player],
- &grenadeRect[player], &myRect, &myRect, &grenadeRect[player] );
-
- grenadeFrame[player]++;
-
- SDLU_ReleaseSurface( playerSpriteSurface[player] );
- }
-
- if( !busy && role[player] == kKillBlobs )
- {
- blobTime[player] = GameTickCount( );
- halfway[player] = false;
- role[player] = kDropBlobs;
- }
-}
-
-int SizeUp( signed char myGrid[kGridAcross][kGridDown], int x, int y, int color )
-{
- int total;
-
- total = GetChainSize( myGrid, x, y, color );
- CleanSize( myGrid, x, y, color );
-
- return total;
-}
-
-int GetChainSize( signed char myGrid[kGridAcross][kGridDown], int x, int y, int color )
-{
- int total;
-
- if( (x<0) || (x>=kGridAcross) || (y<0) || (y>=kGridDown) ) return 0;
- if( myGrid[x][y] != color ) return 0;
-
- myGrid[x][y] = -color;
-
- total = 1 + GetChainSize( myGrid, x-1, y, color )
- + GetChainSize( myGrid, x+1, y, color )
- + GetChainSize( myGrid, x, y-1, color )
- + GetChainSize( myGrid, x, y+1, color );
-
- return total;
-}
-
-void CleanWithPolish( signed char myGrid[kGridAcross][kGridDown], signed char polish[kGridAcross][kGridDown], int x, int y, int color )
-{
- if( (x<0) || (x>=kGridAcross) || (y<0) || (y>=kGridDown) ) return;
-
- if( myGrid[x][y] == -color )
- {
- myGrid[x][y] = color;
- polish[x][y] = true;
-
- CleanWithPolish( myGrid, polish, x-1, y, color );
- CleanWithPolish( myGrid, polish, x+1, y, color );
- CleanWithPolish( myGrid, polish, x, y-1, color );
- CleanWithPolish( myGrid, polish, x, y+1, color );
- }
-}
-
-void CleanSize( signed char myGrid[kGridAcross][kGridDown], int x, int y, int color )
-{
- if( (x<0) || (x>=kGridAcross) || (y<0) || (y>=kGridDown) ) return;
-
- if( myGrid[x][y] == -color )
- {
- myGrid[x][y] = color;
-
- CleanSize( myGrid, x-1, y, color );
- CleanSize( myGrid, x+1, y, color );
- CleanSize( myGrid, x, y-1, color );
- CleanSize( myGrid, x, y+1, color );
- }
-}
-
-void CleanChunks( int player, int x, int y, int level, int style )
-{
- int count, color, type;
- MRect chunkRect;
-
- SDLU_AcquireSurface( playerSpriteSurface[player] );
-
- for( count=-3; count<=3; count++ )
- {
- if( count != 0 )
- {
- if( level > 0 )
- {
- CalcBlobRect( x, y, &chunkRect );
- GetZapStyle( player, &chunkRect, &color, &type, count, level-1, style );
- CleanSpriteArea( player, &chunkRect );
- }
-
- if( level < kZapFrames )
- {
- CalcBlobRect( x, y, &chunkRect );
- GetZapStyle( player, &chunkRect, &color, &type, count, level, style );
- CleanSpriteArea( player, &chunkRect );
- }
- }
- }
-
- SDLU_ReleaseSurface( playerSpriteSurface[player] );
-}
-
-void DrawChunks( int player, int x, int y, int level, int style )
-{
- int count, color, type;
- MRect chunkRect;
-
- SDLU_AcquireSurface( playerSpriteSurface[player] );
-
- for( count=-3; count<=3; count++ )
- {
- if( count != 0 )
- {
- CalcBlobRect( x, y, &chunkRect );
- color = grid[player][x][y];
- GetZapStyle( player, &chunkRect, &color, &type, count, level, style );
- SurfaceDrawSprite( &chunkRect, color, type );
- }
- }
-
- SDLU_ReleaseSurface( playerSpriteSurface[player] );
-}
-
-void CleanSplat( int player, int x, int y, int level )
-{
- int count, color, type;
- MRect chunkRect;
-
- SDLU_AcquireSurface( playerSpriteSurface[player] );
-
- for( count=-2; count<=2; count++ )
- {
- if( count != 0 )
- {
- if( level > 0 )
- {
- CalcBlobRect( x, y, &chunkRect );
- GetZapStyle( player, &chunkRect, &color, &type, count, level-1, 4 );
- CleanSpriteArea( player, &chunkRect );
- }
-
- if( level < kZapFrames )
- {
- CalcBlobRect( x, y, &chunkRect );
- GetZapStyle( player, &chunkRect, &color, &type, count, level, 4 );
- CleanSpriteArea( player, &chunkRect );
- }
- }
- }
-
- SDLU_ReleaseSurface( playerSpriteSurface[player] );
-}
-
-void DrawSplat( int player, int x, int y, int level )
-{
- int count, color = kGray, type;
- MRect chunkRect;
-
- SDLU_AcquireSurface( playerSpriteSurface[player] );
-
- for( count=-2; count<=2; count++ )
- {
- if( level < kZapFrames && count != 0 )
- {
- CalcBlobRect( x, y, &chunkRect );
- GetZapStyle( player, &chunkRect, &color, &type, count, level, 4 );
- SurfaceDrawAlpha( &chunkRect, kGray, kLight, type );
- }
- }
-
- SDLU_ReleaseSurface( playerSpriteSurface[player] );
-}
-
-void InitZapStyle( void )
-{
- int count, which;
- double x;
- const double position[kZapFrames] = {0, 10, 20, 28, 35, 42, 48, 54, 60, 64, 68, 70, 72, 73, 73, 74, 74, 75, 75, 75};
- const double offset[7] = {-30, -50, -70, 0, -110, -130, -150};
-
- zapFont = GetFont( picZapFont );
- zapOutline = GetFont( picZapOutlineFont );
-
- for( count=0; count<kZapFrames; count++ )
- {
- for( which=0; which<7; which++ )
- {
- x = d2r(offset[which]);
-
- zapOffsetX[which][count] = (int) floor( 0.5 + position[count] * cos( x ) );
- zapOffsetY[which][count] = (int) floor( 0.5 + position[count] * sin( x ) );
- }
- }
-}
-
-
-void GetZapStyle( int player, MRect *myRect, int *color, int *type, int which, int level, int style )
-{
- const int chunkGraphic[] = { kSquish1, kSquish1, kSquish1, kSquish1, kSquish1,
- kSquish2, kSquish2, kSquish2, kSquish2, kSquish2,
- kSquish3, kSquish3, kSquish3, kSquish3, kSquish3,
- kSquish4, kSquish4, kSquish4, kSquish4, kSquish4 };
-
- (void) color; // later
- *type = chunkGraphic[level];
-
- switch( style )
- {
- case 0:
- {
- const int direction[7][2] = { {0, -2}, {-2,-1}, {-2,1}, {0,0}, {2,-1}, {2,1}, {0, 2} };
- const int position[kZapFrames] = {0, 5, 9, 13, 17, 21, 24, 26, 30, 33, 35, 37, 39, 41, 42, 43, 43, 44, 44, 44 };
-
- OffsetMRect( myRect, direction[which+3][0] * position[level],
- direction[which+3][1] * position[level] );
- break;
- }
-
-
- case 1:
- {
- const int xVelocity = 3;
- const int yOffset[3][kZapFrames] = { { -4, -8, -12, -17, -22, -26, -30, -33, -36, -39, -41, -42, -43, -44, -44, -44, -43, -42, -41, -39 },
- { -4, -7, -10, -14, -18, -21, -23, -25, -26, -27, -27, -27, -26, -25, -23, -21, -18, -14, -10, -7 },
- { -2, -4, -5, -6, -7, -8, -9, -10, -10, -11, -11, -11, -10, -9, -8, -7, -6, -5, -3, -1 } };
-
- OffsetMRect( myRect, xVelocity * level * which, yOffset[abs(which)-1][level] );
-
- break;
- }
-
- case 2:
- {
- const int position[kZapFrames] = {0, 5, 9, 13, 17, 21, 24, 27, 30, 33, 35, 37, 39, 41, 42, 43, 43, 44, 44, 44 };
-
- OffsetMRect( myRect, 0, position[level] * which );
- break;
- }
-
- case 3:
- {
- double fLevel = ((double)level) / 2;
- OffsetMRect( myRect, (int)((player? -1.0: 1.0) * abs(which) * fLevel * (fLevel-1)), (int)((which-3) * fLevel) );
- break;
- }
-
- case 4:
- {
- OffsetMRect( myRect, zapOffsetX[which+3][level],
- zapOffsetY[which+3][level] );
-
- break;
- }
- }
-}