mirror of
https://github.com/jeremysrand/a2bejwld.git
synced 2024-06-09 21:29:31 +00:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
836d4fbc21 | ||
|
78d451657e | ||
|
b477317279 | ||
|
8bb8f4511b | ||
|
3861bfc00c | ||
|
ab895a6d88 | ||
|
8a7c234e61 | ||
|
bc1cbc975c | ||
|
e21c7375f6 | ||
|
1d5eb0a636 | ||
|
d8ec0349c5 | ||
|
0a5c8b5fe3 | ||
|
49ccd2bfdc |
|
@ -1,10 +1,10 @@
|
|||
A2Bejwld
|
||||
Apple // Bejeweled
|
||||
========
|
||||
|
||||
This is an implementation of Bejeweled written for the Apple //. It is my HackFest entry at KansasFest 2016.
|
||||
|
||||
![A2Bejwld Screenshot](/a2bejwld.png "A2Bejwld Screenshot")
|
||||
![A2Bejwld Screenshot](/a2bejwld.png "Apple // Bejeweled Screenshot")
|
||||
|
||||
[Download a disk image](https://github.com/jeremysrand/a2bejwld/releases/download/2.4/a2bejwld.dsk)
|
||||
[Download a disk image](https://github.com/jeremysrand/a2bejwld/releases/download/2.7/a2bejwld.dsk)
|
||||
|
||||
[Watch the YouTube video](https://youtu.be/yseAGBzREik)
|
||||
|
|
Binary file not shown.
|
@ -7,12 +7,12 @@
|
|||
<key>Binary.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
<integer>3</integer>
|
||||
</dict>
|
||||
<key>DiskImage.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>a2bejwld.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
@ -22,7 +22,7 @@
|
|||
<key>doNotBuild.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>3</integer>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
|
|
@ -265,17 +265,6 @@ void swapSquares(tSquare square1, tGemType gemType1, bool starred1,
|
|||
temp = y2;
|
||||
y2 = y1;
|
||||
y1 = temp;
|
||||
|
||||
#if 0
|
||||
// We don't need to swap square numbers. The code from here on
|
||||
// doesn't distinguish between the two square numbers. So, save
|
||||
// some time and don't swap.
|
||||
//
|
||||
// Be careful if this assumption is no longer true.
|
||||
temp = square2;
|
||||
square2 = square1;
|
||||
square1 = temp;
|
||||
#endif
|
||||
|
||||
temp = gemType2;
|
||||
gemType2 = gemType1;
|
||||
|
|
|
@ -19,6 +19,16 @@ extern void __fastcall__ clearDblLoRes(void);
|
|||
extern void __fastcall__ unshowDblLoRes(void);
|
||||
extern void __fastcall__ mixedTextMode(void);
|
||||
|
||||
// The Apple //e card does not implement double lores correctly. The colours
|
||||
// used on the aux bank need to be shifted but the //e card expects unshifted
|
||||
// colour values (ie the same as those on the main. This function is called
|
||||
// when the game detects it is not running on a //c or //gs. I would like to
|
||||
// get_ostype() from the cc65 runtime but it doesn't work reliably for detecting
|
||||
// the //e card. So I put in my own detection based on the technote. If the
|
||||
// function detects it is runing on a //e card, it causes the graphics
|
||||
// routines to use the same colours in the main and aux banks.
|
||||
extern void __fastcall__ setBuggyDblLoRes(void);
|
||||
|
||||
extern void __fastcall__ drawBgSquare(tSquare square);
|
||||
|
||||
extern void __fastcall__ drawGem(tSquare square);
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
.export _explodeGemFrame1, _explodeGemFrame2
|
||||
.export _explodeGemFrame3, _explodeGemFrame4
|
||||
.export _explodeGemFrame5, _explodeGemFrame6
|
||||
|
||||
.export _setBuggyDblLoRes
|
||||
|
||||
.include "apple2.inc"
|
||||
|
||||
|
@ -909,6 +911,60 @@ xPos: .BYTE $0
|
|||
square: .BYTE $0
|
||||
.endproc
|
||||
|
||||
.proc _setBuggyDblLoRes
|
||||
|
||||
; Unfortunately, there is a bug in get_ostype() in cc65 with detecting the Apple //e card.
|
||||
; There is a version byte in the ROM of the Apple //e card and the tech note describing
|
||||
; machine detection implies it is 0. The first version of the Mac SW for the card maybe used
|
||||
; 0 but for sure there are versions 2 and 3 out there also. But cc65 tests for 0 specifically.
|
||||
; That causes it to detect a Apple //e card with version greater than 0 as an Apple //e
|
||||
; enhanced.
|
||||
;
|
||||
; Combine this with the fact that double lores graphics on the //e card is broken and I have
|
||||
; a problem. So, rather than use get_ostype() to detect the //e card, I am detecting it myself
|
||||
; below based on what the tech note says. If I find the game is running on the //e card, then
|
||||
; I remap the colours used in aux memory to look correct on that HW.
|
||||
;
|
||||
; The bug in cc65 has been sent as a pull request back to that project for a fix here:
|
||||
; https://github.com/cc65/cc65/pull/1013
|
||||
; Once this is fixed and I adopt a newer version of cc65 in this project, I can clean up the
|
||||
; HW detection problem.
|
||||
;
|
||||
; Next I will need to contact Apple to get a fix for the double lores graphics on the //e card...
|
||||
|
||||
bit $c082
|
||||
|
||||
lda $fbb3
|
||||
cmp #$6
|
||||
bne @L3
|
||||
|
||||
lda $fbc0
|
||||
cmp #$e0
|
||||
bne @L3
|
||||
|
||||
lda $fbdd
|
||||
cmp #$02
|
||||
bne @L3
|
||||
|
||||
ldx #63
|
||||
@L1:
|
||||
lda bgColor,X
|
||||
sta bgAuxColor,X
|
||||
dex
|
||||
bpl @L1
|
||||
|
||||
ldx #8
|
||||
@L2:
|
||||
lda gemColours,X
|
||||
sta gemAuxColours,X
|
||||
dex
|
||||
bpl @L2
|
||||
|
||||
@L3:
|
||||
bit $c080
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
.DATA
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ static tJoyCallbacks *gJoyCallbacks = NULL;
|
|||
|
||||
static tJoyState gJoyState = {
|
||||
JOY_POS_CENTER,
|
||||
false,
|
||||
false
|
||||
};
|
||||
|
||||
|
@ -52,17 +51,15 @@ void initJoystick(tJoyCallbacks *callbacks)
|
|||
}
|
||||
|
||||
|
||||
bool isButtonPressed(tJoyButtonNum buttonNum)
|
||||
bool isButtonPressed(void)
|
||||
{
|
||||
if (buttonNum == JOY_BUTTON_0) {
|
||||
__asm__ volatile("LDA %w", BTN0);
|
||||
__asm__ volatile("STA %v", gJoystickTemp);
|
||||
} else if (buttonNum == JOY_BUTTON_1) {
|
||||
__asm__ volatile("LDA %w", BTN1);
|
||||
__asm__ volatile("STA %v", gJoystickTemp);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
__asm__ volatile("LDA %w", BTN0);
|
||||
__asm__ volatile("STA %v", gJoystickTemp);
|
||||
if (gJoystickTemp > 127)
|
||||
return true;
|
||||
|
||||
__asm__ volatile("LDA %w", BTN1);
|
||||
__asm__ volatile("STA %v", gJoystickTemp);
|
||||
return ((gJoystickTemp > 127) ? true : false);
|
||||
}
|
||||
|
||||
|
@ -123,8 +120,7 @@ static void readJoystickState(tJoyState *state)
|
|||
pos = JOY_POS_RIGHT;
|
||||
}
|
||||
|
||||
state->button0 = isButtonPressed(0);
|
||||
state->button1 = isButtonPressed(1);
|
||||
state->button = isButtonPressed();
|
||||
|
||||
if (axisUpDown < LOWER_THRESHOLD) {
|
||||
switch (pos) {
|
||||
|
@ -157,8 +153,7 @@ static void readJoystickState(tJoyState *state)
|
|||
|
||||
static bool joystickStateChanged(tJoyState *state1, tJoyState *state2) {
|
||||
if ((state1->position != state2->position) ||
|
||||
(state1->button0 != state2->button0) ||
|
||||
(state1->button1 != state2->button1)) {
|
||||
(state1->button != state2->button)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -26,21 +26,14 @@
|
|||
#define JOY_POS_DOWN_RIGHT 8
|
||||
#define NUM_JOY_POSITIONS 9
|
||||
|
||||
#define JOY_BUTTON_0 0
|
||||
#define JOY_BUTTON_1 1
|
||||
#define NUM_JOY_BUTTONS 2
|
||||
|
||||
|
||||
// Typedefs
|
||||
|
||||
typedef int8_t tJoyButtonNum;
|
||||
|
||||
typedef int8_t tJoyPos;
|
||||
|
||||
typedef struct tJoyState {
|
||||
tJoyPos position;
|
||||
bool button0;
|
||||
bool button1;
|
||||
bool button;
|
||||
} tJoyState;
|
||||
|
||||
typedef struct tJoyCallbacks {
|
||||
|
@ -64,6 +57,6 @@ typedef struct tJoyCallbacks {
|
|||
|
||||
extern void initJoystick(tJoyCallbacks *callbacks);
|
||||
|
||||
extern bool isButtonPressed(tJoyButtonNum buttonNum);
|
||||
extern bool isButtonPressed(void);
|
||||
|
||||
extern bool pollJoystick(void);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "dbllores.h"
|
||||
#include "machine.h"
|
||||
#include "vbl.h"
|
||||
|
||||
|
@ -32,24 +33,9 @@ static tMachineGSSpeed gOldSpeed = GS_SPEED_SLOW;
|
|||
// Implementation
|
||||
|
||||
|
||||
static bool machineIs2c(void)
|
||||
static bool machineIs2GS(uint8_t machineType)
|
||||
{
|
||||
switch (get_ostype()) {
|
||||
case APPLE_IIC:
|
||||
case APPLE_IIC35:
|
||||
case APPLE_IICEXP:
|
||||
case APPLE_IICREV:
|
||||
case APPLE_IICPLUS:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool machineIs2GS(void)
|
||||
{
|
||||
switch (get_ostype()) {
|
||||
switch (machineType) {
|
||||
case APPLE_IIGS:
|
||||
case APPLE_IIGS1:
|
||||
case APPLE_IIGS3:
|
||||
|
@ -86,18 +72,25 @@ static tMachineGSSpeed setGSSpeed(tMachineGSSpeed newSpeed)
|
|||
|
||||
void initMachine(void)
|
||||
{
|
||||
if (machineIs2c()) {
|
||||
uint8_t machineType = get_ostype();
|
||||
|
||||
if ((machineType == APPLE_IIC) ||
|
||||
(machineType == APPLE_IIC35) ||
|
||||
(machineType == APPLE_IICEXP) ||
|
||||
(machineType == APPLE_IICREV) ||
|
||||
(machineType == APPLE_IICPLUS)) {
|
||||
gVblWait = vblWait2c;
|
||||
} else if (machineIs2GS()) {
|
||||
} else if (machineIs2GS(machineType)) {
|
||||
vblInit2gs();
|
||||
gOldSpeed = setGSSpeed(GS_SPEED_SLOW);
|
||||
}
|
||||
} else
|
||||
setBuggyDblLoRes();
|
||||
}
|
||||
|
||||
|
||||
void uninitMachine(void)
|
||||
{
|
||||
if (machineIs2GS()) {
|
||||
if (machineIs2GS(get_ostype())) {
|
||||
setGSSpeed(gOldSpeed);
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -216,7 +216,7 @@ bool mockingBoardSpeak(uint8_t *data, uint16_t dataLen)
|
|||
return false;
|
||||
|
||||
mockingBoardSpeechData = data;
|
||||
mockingBoardSpeechLen = dataLen + 1;
|
||||
mockingBoardSpeechLen = dataLen;
|
||||
mockingBoardSpeakPriv();
|
||||
|
||||
return true;
|
||||
|
|
|
@ -99,14 +99,14 @@ readChip:
|
|||
lda #$00
|
||||
sta $80
|
||||
sta $82 ; type
|
||||
ldx #$C1
|
||||
ldx #$C7
|
||||
@slotLoop:
|
||||
stx $81
|
||||
ldy #$04 ; 6522 #1 $Cx04
|
||||
jsr @timercheck
|
||||
beq @foundI
|
||||
inx
|
||||
cpx #$C8
|
||||
dex
|
||||
cpx #$C0
|
||||
bne @slotLoop
|
||||
ldx #00 ; not found
|
||||
jmp @cleanup
|
||||
|
@ -117,12 +117,12 @@ readChip:
|
|||
beq @foundII
|
||||
|
||||
ldy #$0C
|
||||
sty @mb_smc3 + 1
|
||||
sty @mb_smc1 + 1
|
||||
iny
|
||||
sty @mb_smc8 + 1
|
||||
sty @mb_smc10 + 1
|
||||
iny
|
||||
sty @mb_smc7 + 1
|
||||
sty @mb_smc11 + 1
|
||||
sty @mb_smc5 + 1
|
||||
sty @mb_smc14 + 1
|
||||
|
||||
.BYTE $2C ; Hide next 2 bytes using a BIT opcode
|
||||
@foundII: ; stereo
|
||||
|
@ -142,6 +142,7 @@ readChip:
|
|||
sta @mb_smc11 + 2
|
||||
sta @mb_smc12 + 2
|
||||
sta @mb_smc13 + 2
|
||||
sta @mb_smc14 + 2
|
||||
|
||||
; detect speech chip
|
||||
|
||||
|
@ -151,25 +152,20 @@ readChip:
|
|||
lda #>@mb_irq
|
||||
sta $3ff
|
||||
|
||||
lda #0
|
||||
@mb_smc1:
|
||||
sta $c403
|
||||
@mb_smc2:
|
||||
sta $c402
|
||||
lda #$0c
|
||||
@mb_smc3:
|
||||
@mb_smc1:
|
||||
sta $c48c
|
||||
lda #$80
|
||||
@mb_smc4:
|
||||
@mb_smc2:
|
||||
sta $c443
|
||||
lda #$c0
|
||||
@mb_smc5:
|
||||
@mb_smc3:
|
||||
sta $c440
|
||||
lda #$70
|
||||
@mb_smc6:
|
||||
@mb_smc4:
|
||||
sta $c443
|
||||
lda #$82
|
||||
@mb_smc7:
|
||||
@mb_smc5:
|
||||
sta $c48e
|
||||
|
||||
ldx #0
|
||||
|
@ -191,11 +187,33 @@ readChip:
|
|||
sei
|
||||
ror $82
|
||||
|
||||
lda $81
|
||||
and #7
|
||||
ldy #$ff
|
||||
@mb_smc6:
|
||||
sty $c403
|
||||
lda #$7
|
||||
@mb_smc7:
|
||||
sta $c402
|
||||
@mb_smc8:
|
||||
sty $c483
|
||||
@mb_smc9:
|
||||
sta $c482
|
||||
|
||||
and $81
|
||||
ora $82
|
||||
tax
|
||||
|
||||
iny
|
||||
sty $80
|
||||
tya
|
||||
sta ($80),y
|
||||
lda #4
|
||||
sta ($80),y
|
||||
tya
|
||||
ldy #$80
|
||||
sta ($80),y
|
||||
lda #4
|
||||
sta ($80),y
|
||||
|
||||
@cleanup:
|
||||
lda zp80Backup
|
||||
sta $80
|
||||
|
@ -223,24 +241,21 @@ readChip:
|
|||
|
||||
@mb_irq:
|
||||
lda #2
|
||||
@mb_smc8:
|
||||
@mb_smc10:
|
||||
sta $c48d
|
||||
lda #$80
|
||||
@mb_smc11:
|
||||
sta $c443
|
||||
lda #0
|
||||
@mb_smc9:
|
||||
@mb_smc12:
|
||||
sta $c440
|
||||
lda #$70
|
||||
@mb_smc10:
|
||||
@mb_smc13:
|
||||
sta $c443
|
||||
sta $80
|
||||
lda #2
|
||||
@mb_smc11:
|
||||
@mb_smc14:
|
||||
sta $c48e
|
||||
lda #$ff
|
||||
@mb_smc12:
|
||||
sta $c403
|
||||
lda #7
|
||||
@mb_smc13:
|
||||
sta $c402
|
||||
lda $45
|
||||
rti
|
||||
|
||||
|
@ -287,11 +302,6 @@ irq2Backup: .BYTE $00
|
|||
|
||||
.proc _mockingBoardSpeakPriv
|
||||
sei
|
||||
lda #$00
|
||||
ldx #DDRA
|
||||
jsr writeChip
|
||||
ldx #DDRB
|
||||
jsr writeChip
|
||||
|
||||
; Get the starting address of the data and store in the work pointer
|
||||
lda _mockingBoardSpeechData+1
|
||||
|
@ -376,6 +386,9 @@ irq2Backup: .BYTE $00
|
|||
@L5:
|
||||
|
||||
; If at the end, turn everything off. Store a pause phoneme.
|
||||
lda #$80
|
||||
ldx #CTTRAMP
|
||||
jsr writeChip
|
||||
lda #$00
|
||||
ldx #DURPHON
|
||||
jsr writeChip
|
||||
|
@ -394,12 +407,6 @@ irq2Backup: .BYTE $00
|
|||
lda #$02
|
||||
ldx #IER
|
||||
jsr writeChip
|
||||
lda #$FF
|
||||
ldx #DDRA
|
||||
jsr writeChip
|
||||
lda #$07
|
||||
ldx #DDRB
|
||||
jsr writeChip
|
||||
|
||||
@L2:
|
||||
; Set the carry flag to indicate we handled the interrupt and return to the caller.
|
||||
|
|
326
a2bejwld/ui.c
326
a2bejwld/ui.c
|
@ -8,6 +8,7 @@
|
|||
|
||||
|
||||
#include <conio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -26,20 +27,36 @@
|
|||
// Defines
|
||||
|
||||
#define SAVE_OPTIONS_FILE "A2BEJWLD.OPTS"
|
||||
#define VERSION "v2.4"
|
||||
#define VERSION "v2.7"
|
||||
|
||||
#define OPTIONS_VERSION_UNSAVED 0
|
||||
#define OPTIONS_VERSION 2
|
||||
#define OPTIONS_VERSION_V2 2
|
||||
#define OPTIONS_VERSION 3
|
||||
|
||||
#define OPTION_JOYSTICK_ENABLED (1 << 0)
|
||||
#define OPTION_MOUSE_ENABLED (1 << 1)
|
||||
#define OPTION_SOUND_ENABLED (1 << 2)
|
||||
#define OPTION_MOCKINGBOARD_ENABLED (1 << 3)
|
||||
#define OPTION_MOCKINGBOARD_SPEECH_ENABLED (1 << 4)
|
||||
|
||||
// Typedefs
|
||||
|
||||
typedef struct tGameOptions {
|
||||
typedef struct tGameOptionsV2 {
|
||||
uint8_t optionsVersion;
|
||||
bool enableJoystick;
|
||||
bool enableMouse;
|
||||
bool enableSound;
|
||||
bool enableMockingboard;
|
||||
bool enableMockingboardSpeech;
|
||||
} tGameOptionsV2;
|
||||
|
||||
typedef struct tGameOptions {
|
||||
uint8_t optionsVersion;
|
||||
uint8_t flags;
|
||||
char upChar;
|
||||
char downChar;
|
||||
char leftChar;
|
||||
char rightChar;
|
||||
} tGameOptions;
|
||||
|
||||
|
||||
|
@ -104,27 +121,32 @@ static bool gShouldSave = false;
|
|||
|
||||
static tGameOptions gGameOptions = {
|
||||
OPTIONS_VERSION_UNSAVED, // optionsVersion
|
||||
false, // enableJoystick
|
||||
true, // enableMouse
|
||||
true, // enableSound
|
||||
true, // enableMockingboard
|
||||
true // enableMockingboardSpeech
|
||||
(OPTION_MOUSE_ENABLED | OPTION_SOUND_ENABLED | OPTION_MOCKINGBOARD_ENABLED | OPTION_MOCKINGBOARD_SPEECH_ENABLED), // flags
|
||||
'I', // upChar
|
||||
'M', // downChar
|
||||
'J', // leftChar
|
||||
'K' // rightChar
|
||||
};
|
||||
|
||||
|
||||
// Implementation
|
||||
|
||||
|
||||
static void printChar (char ch)
|
||||
{
|
||||
if (ch == '\n')
|
||||
ch = '\r';
|
||||
ch |= 0x80;
|
||||
cout(ch);
|
||||
}
|
||||
|
||||
static void printString(char * buffer)
|
||||
{
|
||||
char ch;
|
||||
|
||||
while (*buffer != '\0') {
|
||||
ch = *buffer;
|
||||
if (ch == '\n')
|
||||
ch = '\r';
|
||||
ch |= 0x80;
|
||||
cout(ch);
|
||||
printChar(ch);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +162,7 @@ static void printInteger(uint16_t val)
|
|||
|
||||
static void badThingHappened(void)
|
||||
{
|
||||
if (gGameOptions.enableSound)
|
||||
if ((gGameOptions.flags & OPTION_SOUND_ENABLED) != 0)
|
||||
printString("\007");
|
||||
}
|
||||
|
||||
|
@ -179,7 +201,7 @@ static bool loadOptions(void)
|
|||
|
||||
fclose(optionsFile);
|
||||
|
||||
// If we are upgrading from v1 of the options file, then:
|
||||
// If we are upgrading from v1 to v2 of the options file, then:
|
||||
// - Force the mouse option on. This option is now only used to disable the mouse when one is
|
||||
// present. When no mouse is installed, this option does nothing.
|
||||
// - There used to be a tSlot of the mockingboard where we now have the enableMockingboard boolean.
|
||||
|
@ -187,10 +209,34 @@ static bool loadOptions(void)
|
|||
// - There used to be a boolean to enable/disable the speech chip on the mockingboard. It was only
|
||||
// true if the user enabled it. Now that we can detect the speech chip, the value is default true
|
||||
// and the user can disable speech if they want.
|
||||
if (gGameOptions < OPTIONS_VERSION) {
|
||||
gGameOptions.enableMouse = true;
|
||||
gGameOptions.enableMockingboard = true;
|
||||
gGameOptions.enableMockingboardSpeech = true;
|
||||
if (gGameOptions.optionsVersion < OPTIONS_VERSION) {
|
||||
tGameOptionsV2 * oldOptions = (tGameOptionsV2 *)&gGameOptions;
|
||||
if (oldOptions->enableJoystick)
|
||||
gGameOptions.flags = OPTION_JOYSTICK_ENABLED;
|
||||
else
|
||||
gGameOptions.flags = 0;
|
||||
|
||||
if (oldOptions->enableMouse)
|
||||
gGameOptions.flags |= OPTION_MOUSE_ENABLED;
|
||||
|
||||
if (oldOptions->enableSound)
|
||||
gGameOptions.flags |= OPTION_SOUND_ENABLED;
|
||||
|
||||
if (oldOptions->enableMockingboard)
|
||||
gGameOptions.flags |= OPTION_MOCKINGBOARD_ENABLED;
|
||||
|
||||
if (oldOptions->enableMockingboardSpeech)
|
||||
gGameOptions.flags |= OPTION_MOCKINGBOARD_SPEECH_ENABLED;
|
||||
|
||||
if (gGameOptions.optionsVersion < OPTIONS_VERSION_V2)
|
||||
gGameOptions.flags |= (OPTION_MOUSE_ENABLED | OPTION_MOCKINGBOARD_ENABLED | OPTION_MOCKINGBOARD_SPEECH_ENABLED);
|
||||
|
||||
gGameOptions.upChar = 'I';
|
||||
gGameOptions.downChar = 'M';
|
||||
gGameOptions.leftChar = 'J';
|
||||
gGameOptions.rightChar = 'K';
|
||||
|
||||
gGameOptions.optionsVersion = OPTIONS_VERSION;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -206,11 +252,12 @@ static void applyNewOptions(tGameOptions *newOptions)
|
|||
|
||||
printString("\n\n\n Saving options...");
|
||||
|
||||
if ((gGameOptions.enableSound != newOptions->enableSound) ||
|
||||
(gGameOptions.enableMockingboard != newOptions->enableMockingboard) ||
|
||||
(gGameOptions.enableMockingboardSpeech != newOptions->enableMockingboardSpeech)) {
|
||||
if ((gGameOptions.flags & (OPTION_SOUND_ENABLED | OPTION_MOCKINGBOARD_ENABLED | OPTION_MOCKINGBOARD_SPEECH_ENABLED)) !=
|
||||
(newOptions->flags & (OPTION_SOUND_ENABLED | OPTION_MOCKINGBOARD_ENABLED | OPTION_MOCKINGBOARD_SPEECH_ENABLED))) {
|
||||
// If the sound parameters have changed, then re-init sounds
|
||||
soundInit(newOptions->enableSound, newOptions->enableMockingboard, newOptions->enableMockingboardSpeech);
|
||||
soundInit(((newOptions->flags & OPTION_SOUND_ENABLED) != 0),
|
||||
((newOptions->flags & OPTION_MOCKINGBOARD_ENABLED) != 0),
|
||||
((newOptions->flags & OPTION_MOCKINGBOARD_SPEECH_ENABLED) !=0));
|
||||
}
|
||||
|
||||
memcpy(&gGameOptions, newOptions, sizeof(gGameOptions));
|
||||
|
@ -228,7 +275,13 @@ static void showCursor(void)
|
|||
static void replaceCursor(char ch)
|
||||
{
|
||||
cout(CH_CURS_LEFT);
|
||||
cout(ch | 0x80);
|
||||
printChar(ch);
|
||||
}
|
||||
|
||||
|
||||
static char getKey(void)
|
||||
{
|
||||
return toupper(cgetc());
|
||||
}
|
||||
|
||||
|
||||
|
@ -239,16 +292,14 @@ static bool yorn(void)
|
|||
|
||||
showCursor();
|
||||
while (true) {
|
||||
ch = cgetc();
|
||||
ch = getKey();
|
||||
|
||||
if ((ch == 'N') ||
|
||||
(ch == 'n')) {
|
||||
if (ch == 'N') {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ch == 'Y') ||
|
||||
(ch == 'y'))
|
||||
if (ch == 'Y')
|
||||
break;
|
||||
|
||||
badThingHappened();
|
||||
|
@ -265,9 +316,12 @@ static void getSoundOptions(tGameOptions *newOptions)
|
|||
tSlot slot;
|
||||
|
||||
printString("\n\nEnable sounds? (Y/N) ");
|
||||
newOptions->enableSound = yorn();
|
||||
if (!newOptions->enableSound)
|
||||
if (yorn()) {
|
||||
newOptions->flags |= OPTION_SOUND_ENABLED;
|
||||
} else {
|
||||
newOptions->flags &= ~OPTION_SOUND_ENABLED;
|
||||
return;
|
||||
}
|
||||
|
||||
// If no mockingboard present, don't bother to ask whether to enable/disable it.
|
||||
slot = mockingBoardSlot();
|
||||
|
@ -277,9 +331,12 @@ static void getSoundOptions(tGameOptions *newOptions)
|
|||
printString("\nEnable MockingBoard sound found in slot ");
|
||||
printInteger(slot);
|
||||
printString("? (Y/N) ");
|
||||
newOptions->enableMockingboard = yorn();
|
||||
if (!newOptions->enableMockingboard)
|
||||
if (yorn()) {
|
||||
newOptions->flags |= OPTION_MOCKINGBOARD_ENABLED;
|
||||
} else {
|
||||
newOptions->flags &= ~OPTION_MOCKINGBOARD_ENABLED;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the mockingboard does not have a speech chip, do not prompt whether to
|
||||
// enable/disable it.
|
||||
|
@ -287,7 +344,50 @@ static void getSoundOptions(tGameOptions *newOptions)
|
|||
return;
|
||||
|
||||
printString("\nEnable speech on the Mockingboard? (Y/N) ");
|
||||
newOptions->enableMockingboardSpeech = yorn();
|
||||
if (yorn()) {
|
||||
newOptions->flags |= OPTION_MOCKINGBOARD_SPEECH_ENABLED;
|
||||
} else {
|
||||
newOptions->flags &= ~OPTION_MOCKINGBOARD_SPEECH_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static char getKeyDirection(char *dir, char current, char other1, char other2, char other3)
|
||||
{
|
||||
char ch;
|
||||
|
||||
printString("\nKey for ");
|
||||
printString(dir);
|
||||
printString(" movement (current ");
|
||||
printChar(current);
|
||||
printString(") ");
|
||||
showCursor();
|
||||
while (true) {
|
||||
ch = getKey();
|
||||
if ((isalnum(ch)) &&
|
||||
(ch != 'Q') &&
|
||||
(ch != 'R') &&
|
||||
(ch != 'O') &&
|
||||
(ch != 'H') &&
|
||||
(ch != other1) &&
|
||||
(ch != other2) &&
|
||||
(ch != other3))
|
||||
break;
|
||||
|
||||
badThingHappened();
|
||||
}
|
||||
replaceCursor(ch);
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void getKeyboardOptions(tGameOptions *newOptions)
|
||||
{
|
||||
printChar('\n');
|
||||
newOptions->upChar = getKeyDirection("up", newOptions->upChar, 0, 0, 0);
|
||||
newOptions->downChar = getKeyDirection("down", newOptions->downChar, newOptions->upChar, 0, 0);
|
||||
newOptions->leftChar = getKeyDirection("left", newOptions->leftChar, newOptions->upChar, newOptions->downChar, 0);
|
||||
newOptions->rightChar = getKeyDirection("right", newOptions->rightChar, newOptions->upChar, newOptions->downChar, newOptions->leftChar);
|
||||
}
|
||||
|
||||
|
||||
|
@ -302,6 +402,9 @@ static void selectOptions(void)
|
|||
memcpy(&newOptions, &gGameOptions, sizeof(newOptions));
|
||||
|
||||
while (true) {
|
||||
bool enableSound = ((newOptions.flags & OPTION_SOUND_ENABLED) != 0);
|
||||
bool enableMockingboard = ((newOptions.flags & OPTION_MOCKINGBOARD_ENABLED) != 0);
|
||||
|
||||
clrscr();
|
||||
printString(
|
||||
// 0000000001111111111222222222233333333334444444444555555555566666666667
|
||||
|
@ -309,19 +412,31 @@ static void selectOptions(void)
|
|||
" Apple // Bejeweled\n"
|
||||
" Options\n"
|
||||
"\n"
|
||||
" K - Keyboard control - ");
|
||||
printChar(newOptions.upChar);
|
||||
printChar('\n');
|
||||
printString(" ");
|
||||
printChar(newOptions.leftChar);
|
||||
printChar(' ');
|
||||
printChar(newOptions.rightChar);
|
||||
printChar('\n');
|
||||
printString(" ");
|
||||
printChar(newOptions.downChar);
|
||||
printChar('\n');
|
||||
printString(
|
||||
" J - Joystick control - ");
|
||||
printString(newOptions.enableJoystick ? "Enabled\n" : "Disabled\n");
|
||||
printString(((newOptions.flags & OPTION_JOYSTICK_ENABLED) != 0) ? "Enabled\n" : "Disabled\n");
|
||||
if (hasMouse())
|
||||
{
|
||||
printString(
|
||||
" M - Mouse control - ");
|
||||
printString(newOptions.enableMouse ? "Enabled\n" : "Disabled\n");
|
||||
printString(((newOptions.flags & OPTION_MOUSE_ENABLED) != 0) ? "Enabled\n" : "Disabled\n");
|
||||
}
|
||||
printString(
|
||||
" S - Sound - ");
|
||||
printString(newOptions.enableSound ? "Enabled\n" : "Disabled\n");
|
||||
printString(enableSound ? "Enabled\n" : "Disabled\n");
|
||||
|
||||
if (newOptions.enableSound) {
|
||||
if (enableSound) {
|
||||
tSlot slot = mockingBoardSlot();
|
||||
|
||||
if (slot != 0) {
|
||||
|
@ -329,18 +444,18 @@ static void selectOptions(void)
|
|||
// 0000000001111111111222222222233333333334444444444555555555566666666667
|
||||
// 1234567890123456789012345678901234567890123456789012345678901234567890
|
||||
" MockingBoard - ");
|
||||
printString(newOptions.enableMockingboard ? "Enabled (Slot " : "Disabled (Slot ");
|
||||
printString(enableMockingboard ? "Enabled (Slot " : "Disabled (Slot ");
|
||||
printInteger(slot);
|
||||
printString(")\n");
|
||||
|
||||
if ((newOptions.enableMockingboard) &&
|
||||
if ((enableMockingboard) &&
|
||||
(mockingBoardHasSpeechChip()))
|
||||
{
|
||||
printString(
|
||||
// 0000000001111111111222222222233333333334444444444555555555566666666667
|
||||
// 1234567890123456789012345678901234567890123456789012345678901234567890
|
||||
" Speech - ");
|
||||
printString(newOptions.enableMockingboardSpeech ? "Enabled\n" : "Disabled\n");
|
||||
printString(((newOptions.flags & OPTION_MOCKINGBOARD_SPEECH_ENABLED) != 0) ? "Enabled\n" : "Disabled\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -351,21 +466,22 @@ static void selectOptions(void)
|
|||
" Type a letter to change a setting or any other key to save settings\n"
|
||||
" and continue");
|
||||
|
||||
switch (cgetc()) {
|
||||
case 'j':
|
||||
switch (getKey()) {
|
||||
case 'J':
|
||||
newOptions.enableJoystick = !newOptions.enableJoystick;
|
||||
newOptions.flags ^= OPTION_JOYSTICK_ENABLED;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
case 'S':
|
||||
getSoundOptions(&newOptions);
|
||||
break;
|
||||
|
||||
case 'K':
|
||||
getKeyboardOptions(&newOptions);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
if (hasMouse()) {
|
||||
newOptions.enableMouse = !newOptions.enableMouse;
|
||||
newOptions.flags ^= OPTION_MOUSE_ENABLED;
|
||||
break;
|
||||
}
|
||||
// Fall through. If no mouse, then pressing m is a fall through into the save code.
|
||||
|
@ -392,7 +508,18 @@ void printInstructions(void)
|
|||
" Apple // Bejeweled (" VERSION ")\n"
|
||||
" by Jeremy Rand\n"
|
||||
"\n"
|
||||
" Use I-J-K-M, the arrow keys, joystick or mouse to move your selection.\n"
|
||||
" Use ");
|
||||
|
||||
printChar(gGameOptions.upChar);
|
||||
printChar('-');
|
||||
printChar(gGameOptions.leftChar);
|
||||
printChar('-');
|
||||
printChar(gGameOptions.rightChar);
|
||||
printChar('-');
|
||||
printChar(gGameOptions.downChar);
|
||||
|
||||
printString(
|
||||
" the arrow keys, joystick or mouse to move your selection.\n"
|
||||
" Hold either apple key, joystick or mouse button and move your selection\n"
|
||||
" to swap two jewels and match 3 or more jewels. When you match three\n"
|
||||
" jewels, they disappear and new jewels will drop from the top.\n"
|
||||
|
@ -420,8 +547,7 @@ void printInstructions(void)
|
|||
|
||||
srand(seed);
|
||||
|
||||
switch (cgetc()) {
|
||||
case 'o':
|
||||
switch (getKey()) {
|
||||
case 'O':
|
||||
selectOptions();
|
||||
break;
|
||||
|
@ -609,12 +735,6 @@ static bool swapDir(tDirection dir)
|
|||
}
|
||||
|
||||
|
||||
static bool isAppleButtonPressed(void)
|
||||
{
|
||||
return (isButtonPressed(JOY_BUTTON_0) || isButtonPressed(JOY_BUTTON_1));
|
||||
}
|
||||
|
||||
|
||||
static void endGame(void)
|
||||
{
|
||||
char ch;
|
||||
|
@ -632,18 +752,15 @@ static void endGame(void)
|
|||
|
||||
showCursor();
|
||||
while (true) {
|
||||
ch = cgetc();
|
||||
ch = getKey();
|
||||
switch (ch) {
|
||||
case 'y':
|
||||
case 'Y':
|
||||
replaceCursor(ch);
|
||||
printString("\n");
|
||||
return;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
case CH_ESC:
|
||||
case 'q':
|
||||
case 'Q':
|
||||
replaceCursor(ch);
|
||||
quitGame();
|
||||
|
@ -717,7 +834,9 @@ void initUI(void)
|
|||
|
||||
optionsLoaded = loadOptions();
|
||||
|
||||
soundInit(gGameOptions.enableSound, gGameOptions.enableMockingboard, gGameOptions.enableMockingboardSpeech);
|
||||
soundInit(((gGameOptions.flags & OPTION_SOUND_ENABLED) != 0),
|
||||
((gGameOptions.flags & OPTION_MOCKINGBOARD_ENABLED) != 0),
|
||||
((gGameOptions.flags & OPTION_MOCKINGBOARD_SPEECH_ENABLED) != 0));
|
||||
|
||||
initGameEngine(&gCallbacks);
|
||||
|
||||
|
@ -789,8 +908,7 @@ static bool joystickChangedCallback(tJoyState *oldState, tJoyState *newState)
|
|||
if (oldState->position != JOY_POS_CENTER)
|
||||
return false;
|
||||
|
||||
if ((newState->button0) ||
|
||||
(newState->button1)) {
|
||||
if (newState->button) {
|
||||
switch (newState->position) {
|
||||
case JOY_POS_UP:
|
||||
return swapDir(DIR_UP);
|
||||
|
@ -818,10 +936,7 @@ static bool joystickChangedCallback(tJoyState *oldState, tJoyState *newState)
|
|||
|
||||
static bool joystickNoChangeCallback(tJoyState *oldState)
|
||||
{
|
||||
if (oldState->button0)
|
||||
return false;
|
||||
|
||||
if (oldState->button1)
|
||||
if (oldState->button)
|
||||
return false;
|
||||
|
||||
joystickMove(oldState->position);
|
||||
|
@ -837,60 +952,56 @@ static bool pollKeyboard(void)
|
|||
if (!kbhit())
|
||||
return result;
|
||||
|
||||
ch = cgetc();
|
||||
ch = getKey();
|
||||
if (ch == gGameOptions.upChar)
|
||||
ch = 0x0b;
|
||||
else if (ch == gGameOptions.downChar)
|
||||
ch = 0x0a;
|
||||
else if (ch == gGameOptions.leftChar)
|
||||
ch = CH_CURS_LEFT;
|
||||
else if (ch == gGameOptions.rightChar)
|
||||
ch = CH_CURS_RIGHT;
|
||||
|
||||
if ((ch < 128) &&
|
||||
(isButtonPressed()))
|
||||
ch += 128;
|
||||
|
||||
switch (ch) {
|
||||
case 'i':
|
||||
case 'I':
|
||||
// case CH_CURS_UP:
|
||||
case 0x0b:
|
||||
if (!isAppleButtonPressed()) {
|
||||
moveDir(DIR_UP);
|
||||
break;
|
||||
}
|
||||
// Fallthrough...
|
||||
moveDir(DIR_UP);
|
||||
break;
|
||||
|
||||
case 139:
|
||||
result = swapDir(DIR_UP);
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
case 'J':
|
||||
case CH_CURS_LEFT:
|
||||
if (!isAppleButtonPressed()) {
|
||||
moveDir(DIR_LEFT);
|
||||
break;
|
||||
}
|
||||
// Fallthrough...
|
||||
moveDir(DIR_LEFT);
|
||||
break;
|
||||
|
||||
case 136:
|
||||
result = swapDir(DIR_LEFT);
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
case 'K':
|
||||
case CH_CURS_RIGHT:
|
||||
if (!isAppleButtonPressed()) {
|
||||
moveDir(DIR_RIGHT);
|
||||
break;
|
||||
}
|
||||
// Fallthrough...
|
||||
moveDir(DIR_RIGHT);
|
||||
break;
|
||||
|
||||
case 149:
|
||||
result = swapDir(DIR_RIGHT);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
// case CH_CURS_DOWN:
|
||||
case 0x0a:
|
||||
if (!isAppleButtonPressed()) {
|
||||
moveDir(DIR_DOWN);
|
||||
break;
|
||||
}
|
||||
// Fallthrough...
|
||||
moveDir(DIR_DOWN);
|
||||
break;
|
||||
|
||||
case 138:
|
||||
result = swapDir(DIR_DOWN);
|
||||
break;
|
||||
|
||||
case CH_ESC:
|
||||
case 'q':
|
||||
case 'Q':
|
||||
if (gShouldSave) {
|
||||
videomode(0x12);
|
||||
|
@ -901,21 +1012,18 @@ static bool pollKeyboard(void)
|
|||
quitGame();
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
case 'R':
|
||||
refreshScore(0);
|
||||
startNewGame();
|
||||
gShouldSave = false;
|
||||
return true;
|
||||
|
||||
case 'o':
|
||||
case 'O':
|
||||
selectOptions();
|
||||
showAndClearDblLoRes();
|
||||
drawBoard();
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case 'H':
|
||||
getHint();
|
||||
break;
|
||||
|
@ -965,6 +1073,14 @@ void playGame(void)
|
|||
drawBoard();
|
||||
speakGo();
|
||||
while (true) {
|
||||
if (gameIsOver()) {
|
||||
endGame();
|
||||
showAndClearDblLoRes();
|
||||
refreshScore(0);
|
||||
startNewGame();
|
||||
gShouldSave = false;
|
||||
}
|
||||
|
||||
resetStarAnim();
|
||||
|
||||
while (true) {
|
||||
|
@ -974,23 +1090,15 @@ void playGame(void)
|
|||
break;
|
||||
}
|
||||
|
||||
if ((gGameOptions.enableJoystick) &&
|
||||
if (((gGameOptions.flags & OPTION_JOYSTICK_ENABLED) != 0) &&
|
||||
(pollJoystick())) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((gGameOptions.enableMouse) &&
|
||||
if (((gGameOptions.flags & OPTION_MOUSE_ENABLED) != 0) &&
|
||||
(pollMouse())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gameIsOver()) {
|
||||
endGame();
|
||||
showAndClearDblLoRes();
|
||||
refreshScore(0);
|
||||
startNewGame();
|
||||
gShouldSave = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user