mirror of
https://github.com/jeremysrand/a2bejwld.git
synced 2026-04-23 20:21:14 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 836d4fbc21 | |||
| 78d451657e | |||
| b477317279 | |||
| 8bb8f4511b | |||
| 3861bfc00c | |||
| ab895a6d88 | |||
| 8a7c234e61 | |||
| bc1cbc975c | |||
| e21c7375f6 | |||
| 1d5eb0a636 | |||
| d8ec0349c5 | |||
| 0a5c8b5fe3 | |||
| 49ccd2bfdc | |||
| d3d97db1f6 | |||
| 20ad7dda1c | |||
| 72fc265e5a |
@@ -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.
|
||||
|
||||

|
||||

|
||||
|
||||
[Download a disk image](https://github.com/jeremysrand/a2bejwld/releases/download/2.2/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)
|
||||
|
||||
Generated
BIN
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>
|
||||
|
||||
@@ -71,7 +71,6 @@ SRCDIRS+=
|
||||
|
||||
# If you want to add arguments to the compile commandline, add them
|
||||
# to this variable:
|
||||
# CFLAGS += -DTOTAL_REPLAY_BUILD
|
||||
CFLAGS += -Os
|
||||
|
||||
# If you want to add arguments to the assembly commandline, add them
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+10
-15
@@ -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;
|
||||
|
||||
+2
-9
@@ -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);
|
||||
|
||||
+14
-21
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,20 +16,8 @@
|
||||
|
||||
// Implementation
|
||||
|
||||
#ifdef TOTAL_REPLAY_BUILD
|
||||
void totalReplayQuit(void)
|
||||
{
|
||||
__asm__ ("BIT $C082");
|
||||
__asm__ ("JMP $100");
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
#ifdef TOTAL_REPLAY_BUILD
|
||||
atexit(totalReplayQuit);
|
||||
#endif
|
||||
|
||||
initUI();
|
||||
|
||||
printInstructions();
|
||||
|
||||
Binary file not shown.
+42
-8
@@ -46,6 +46,9 @@ static uint8_t *gMockDataDirA[NUM_SOUND_CHIPS] = { (uint8_t *)0xc003, (uint8_t *
|
||||
|
||||
static uint8_t gMockingBoardInitialized = false;
|
||||
static uint8_t gMockingBoardSpeechInitialized = false;
|
||||
static uint8_t gMockingBoardSearchDone = false;
|
||||
static tSlot gMockingBoardSlot = 0;
|
||||
static bool gMockingBoardHasSpeech = false;
|
||||
|
||||
|
||||
// Implementation
|
||||
@@ -64,29 +67,47 @@ static uint8_t *mapIOPointer(tSlot slot, uint8_t *ptr)
|
||||
}
|
||||
|
||||
|
||||
void mockingBoardInit(tSlot slot, bool hasSpeechChip)
|
||||
bool mockingBoardInit(void)
|
||||
{
|
||||
tMockingBoardSoundChip soundChip;
|
||||
|
||||
if (!gMockingBoardSearchDone)
|
||||
{
|
||||
gMockingBoardSlot = getMockingBoardSlot();
|
||||
|
||||
if ((gMockingBoardSlot & 0x80) != 0)
|
||||
gMockingBoardHasSpeech = true;
|
||||
|
||||
gMockingBoardSlot &= 0x7;
|
||||
|
||||
gMockingBoardSearchDone = true;
|
||||
}
|
||||
|
||||
if (gMockingBoardSlot == 0)
|
||||
return false;
|
||||
|
||||
if (gMockingBoardInitialized)
|
||||
return true;
|
||||
|
||||
if (sizeof(tMockingSoundRegisters) != 16) {
|
||||
printf("The sound registers must be 16 bytes long!\n");
|
||||
}
|
||||
|
||||
for (soundChip = SOUND_CHIP_1; soundChip < NUM_SOUND_CHIPS; soundChip++) {
|
||||
gMockPortB[soundChip] = mapIOPointer(slot, gMockPortB[soundChip]);
|
||||
gMockPortA[soundChip] = mapIOPointer(slot, gMockPortA[soundChip]);
|
||||
gMockDataDirB[soundChip] = mapIOPointer(slot, gMockDataDirB[soundChip]);
|
||||
gMockDataDirA[soundChip] = mapIOPointer(slot, gMockDataDirA[soundChip]);
|
||||
gMockPortB[soundChip] = mapIOPointer(gMockingBoardSlot, gMockPortB[soundChip]);
|
||||
gMockPortA[soundChip] = mapIOPointer(gMockingBoardSlot, gMockPortA[soundChip]);
|
||||
gMockDataDirB[soundChip] = mapIOPointer(gMockingBoardSlot, gMockDataDirB[soundChip]);
|
||||
gMockDataDirA[soundChip] = mapIOPointer(gMockingBoardSlot, gMockDataDirA[soundChip]);
|
||||
|
||||
*(gMockDataDirA[soundChip]) = 0xff; // Set port A for output
|
||||
*(gMockDataDirB[soundChip]) = 0x7; // Set port B for output
|
||||
}
|
||||
|
||||
if (hasSpeechChip) {
|
||||
if (gMockingBoardHasSpeech) {
|
||||
if (gMockingBoardSpeechInitialized) {
|
||||
mockingBoardSpeechShutdown();
|
||||
}
|
||||
mockingBoardSpeechInit(slot);
|
||||
mockingBoardSpeechInit(gMockingBoardSlot);
|
||||
gMockingBoardSpeechInitialized = true;
|
||||
} else if (gMockingBoardSpeechInitialized) {
|
||||
mockingBoardSpeechShutdown();
|
||||
@@ -94,6 +115,7 @@ void mockingBoardInit(tSlot slot, bool hasSpeechChip)
|
||||
}
|
||||
|
||||
gMockingBoardInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -108,6 +130,18 @@ void mockingBoardShutdown(void)
|
||||
}
|
||||
|
||||
|
||||
tSlot mockingBoardSlot(void)
|
||||
{
|
||||
return gMockingBoardSlot;
|
||||
}
|
||||
|
||||
|
||||
bool mockingBoardHasSpeechChip(void)
|
||||
{
|
||||
return gMockingBoardHasSpeech;
|
||||
}
|
||||
|
||||
|
||||
static void writeCommand(tMockingBoardSoundChip soundChip, uint8_t command)
|
||||
{
|
||||
volatile uint8_t *ptr = gMockPortB[soundChip];
|
||||
@@ -182,7 +216,7 @@ bool mockingBoardSpeak(uint8_t *data, uint16_t dataLen)
|
||||
return false;
|
||||
|
||||
mockingBoardSpeechData = data;
|
||||
mockingBoardSpeechLen = dataLen + 1;
|
||||
mockingBoardSpeechLen = dataLen;
|
||||
mockingBoardSpeakPriv();
|
||||
|
||||
return true;
|
||||
|
||||
@@ -117,13 +117,15 @@ typedef struct tMockingSoundRegisters {
|
||||
|
||||
// API
|
||||
|
||||
extern uint8_t getMockingBoardSlot(void);
|
||||
extern void mockingBoardInit(tSlot slot, bool hasSpeechChip);
|
||||
extern bool mockingBoardInit(void);
|
||||
extern void mockingBoardShutdown(void);
|
||||
|
||||
extern tSlot mockingBoardSlot(void);
|
||||
|
||||
extern void mockingBoardPlaySound(tMockingBoardSpeaker speaker, tMockingSoundRegisters *registers);
|
||||
extern void mockingBoardStopSound(tMockingBoardSpeaker speaker);
|
||||
|
||||
extern bool mockingBoardHasSpeechChip(void);
|
||||
extern bool mockingBoardSpeechIsBusy(void);
|
||||
extern bool mockingBoardSpeechIsPlaying(void);
|
||||
extern bool mockingBoardSpeak(uint8_t *data, uint16_t dataLen);
|
||||
|
||||
@@ -18,6 +18,7 @@ extern uint16_t mockingBoardSpeechLen;
|
||||
extern uint8_t mockingBoardSpeechBusy;
|
||||
extern uint8_t mockingBoardSpeechPlaying;
|
||||
|
||||
extern uint8_t getMockingBoardSlot(void);
|
||||
extern void mockingBoardSpeechInit(uint8_t slot);
|
||||
extern void mockingBoardSpeechShutdown(void);
|
||||
extern void mockingBoardSpeakPriv(void);
|
||||
|
||||
+154
-28
@@ -74,37 +74,146 @@ readChip:
|
||||
; in: none
|
||||
; accelerators should be off
|
||||
; out:
|
||||
; if card was found, A = #$n where n is the slot number of the card, otherwise #$00
|
||||
; if card was found, A = #$?n where n is the slot number of the card, otherwise #$00
|
||||
; and bit 6 = 0 if Mockingboard Sound I found
|
||||
; or bit 6 = 1 if Mockingboard Sound II or "A" found
|
||||
; and bit 7 = 1 if Mockingboard Sound/Speech I or "C" found
|
||||
; flags clobbered
|
||||
; zp $80-$82 clobbered
|
||||
; (jrand - and then restored because I am chicken and afraid of breaking cc65 runtime)
|
||||
; X/Y clobbered
|
||||
;------------------------------------------------------------------------------
|
||||
.proc _getMockingBoardSlot
|
||||
php
|
||||
lda $80
|
||||
sta zp80Backup
|
||||
lda $81
|
||||
sta zp81Backup
|
||||
lda $82
|
||||
sta zp82Backup
|
||||
lda $3fe
|
||||
sta irq1Backup
|
||||
lda $3ff
|
||||
sta irq2Backup
|
||||
|
||||
lda #$00
|
||||
sta $80
|
||||
sta $82 ; type
|
||||
ldx #$C7
|
||||
@slotLoop:
|
||||
stx $81
|
||||
ldy #$04 ; 6522 #1 $Cx04
|
||||
jsr timercheck
|
||||
bne @nextSlot
|
||||
ldy #$84 ; 6522 #2 $Cx84
|
||||
jsr timercheck
|
||||
bne @nextSlot
|
||||
beq @cleanup
|
||||
@nextSlot:
|
||||
jsr @timercheck
|
||||
beq @foundI
|
||||
dex
|
||||
cpx #$C0
|
||||
bne @slotLoop
|
||||
ldx #$00 ; not found
|
||||
ldx #00 ; not found
|
||||
jmp @cleanup
|
||||
|
||||
@foundI: ; sound I or better
|
||||
ldy #$84 ; 6522 #2 $Cx84
|
||||
jsr @timercheck
|
||||
beq @foundII
|
||||
|
||||
ldy #$0C
|
||||
sty @mb_smc1 + 1
|
||||
iny
|
||||
sty @mb_smc10 + 1
|
||||
iny
|
||||
sty @mb_smc5 + 1
|
||||
sty @mb_smc14 + 1
|
||||
|
||||
.BYTE $2C ; Hide next 2 bytes using a BIT opcode
|
||||
@foundII: ; stereo
|
||||
ror $82
|
||||
|
||||
lda $81
|
||||
sta @mb_smc1 + 2
|
||||
sta @mb_smc2 + 2
|
||||
sta @mb_smc3 + 2
|
||||
sta @mb_smc4 + 2
|
||||
sta @mb_smc5 + 2
|
||||
sta @mb_smc6 + 2
|
||||
sta @mb_smc7 + 2
|
||||
sta @mb_smc8 + 2
|
||||
sta @mb_smc9 + 2
|
||||
sta @mb_smc10 + 2
|
||||
sta @mb_smc11 + 2
|
||||
sta @mb_smc12 + 2
|
||||
sta @mb_smc13 + 2
|
||||
sta @mb_smc14 + 2
|
||||
|
||||
; detect speech chip
|
||||
|
||||
sei
|
||||
lda #<@mb_irq
|
||||
sta $3fe
|
||||
lda #>@mb_irq
|
||||
sta $3ff
|
||||
|
||||
lda #$0c
|
||||
@mb_smc1:
|
||||
sta $c48c
|
||||
lda #$80
|
||||
@mb_smc2:
|
||||
sta $c443
|
||||
lda #$c0
|
||||
@mb_smc3:
|
||||
sta $c440
|
||||
lda #$70
|
||||
@mb_smc4:
|
||||
sta $c443
|
||||
lda #$82
|
||||
@mb_smc5:
|
||||
sta $c48e
|
||||
|
||||
ldx #0
|
||||
ldy #0
|
||||
sec
|
||||
cli
|
||||
|
||||
@wait_irq:
|
||||
lda $80
|
||||
bne @got_irq
|
||||
iny
|
||||
bne @wait_irq
|
||||
inx
|
||||
bne @wait_irq
|
||||
clc
|
||||
|
||||
@got_irq:
|
||||
|
||||
sei
|
||||
ror $82
|
||||
|
||||
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
|
||||
@@ -112,25 +221,50 @@ readChip:
|
||||
sta $81
|
||||
lda zp82Backup
|
||||
sta $82
|
||||
lda irq1Backup
|
||||
sta $3fe
|
||||
lda irq2Backup
|
||||
sta $3ff
|
||||
txa
|
||||
and #$07
|
||||
ldx #$00
|
||||
plp
|
||||
rts
|
||||
|
||||
timercheck:
|
||||
lda ($80),y ; read 6522 timer low byte
|
||||
sta $82
|
||||
lda ($80),y ; second time
|
||||
@timercheck:
|
||||
sec
|
||||
sbc $82
|
||||
cmp #$F8 ; looking for (-)8 cycles between reads
|
||||
lda ($80),y ; read 6522 timer low byte
|
||||
sbc ($80),y ; second time
|
||||
cmp #5 ; looking for (-)8 cycles between reads
|
||||
beq :+
|
||||
cmp #$F7 ; FastChip //e clock is different
|
||||
cmp #6 ; FastChip //e clock is different
|
||||
: rts
|
||||
|
||||
@mb_irq:
|
||||
lda #2
|
||||
@mb_smc10:
|
||||
sta $c48d
|
||||
lda #$80
|
||||
@mb_smc11:
|
||||
sta $c443
|
||||
lda #0
|
||||
@mb_smc12:
|
||||
sta $c440
|
||||
lda #$70
|
||||
@mb_smc13:
|
||||
sta $c443
|
||||
sta $80
|
||||
lda #2
|
||||
@mb_smc14:
|
||||
sta $c48e
|
||||
lda $45
|
||||
rti
|
||||
|
||||
; Locals
|
||||
zp80Backup: .BYTE $00
|
||||
zp81Backup: .BYTE $00
|
||||
zp82Backup: .BYTE $00
|
||||
irq1Backup: .BYTE $00
|
||||
irq2Backup: .BYTE $00
|
||||
.endproc
|
||||
|
||||
|
||||
@@ -168,11 +302,6 @@ zp82Backup: .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
|
||||
@@ -257,6 +386,9 @@ zp82Backup: .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
|
||||
@@ -275,12 +407,6 @@ zp82Backup: .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.
|
||||
|
||||
@@ -32,19 +32,13 @@ bool initMouse(tMouseCallbacks *callbacks)
|
||||
if (!gMouseInstalled) {
|
||||
memcpy(&gMouseDrvCallbacks, &mouse_def_callbacks, sizeof(gMouseDrvCallbacks));
|
||||
// This callback is here for the //c VBL which is only detectable
|
||||
// through the mouse interrupt. By registering this as our "show"
|
||||
// through the mouse interrupt. By registering this as our "draw"
|
||||
// function, we can ensure that we get called on our VBL interrupt
|
||||
// and can unblock our VBL wait function.
|
||||
gMouseDrvCallbacks.show = vblIRQCallback;
|
||||
gMouseDrvCallbacks.draw = vblIRQCallback;
|
||||
|
||||
if (mouse_install(&gMouseDrvCallbacks, &a2_mouse_drv) == 0) {
|
||||
gMouseInstalled = true;
|
||||
|
||||
// This is required to ensure that the show callback is called
|
||||
// by the interrupt handler. This whole thing is a bit of a
|
||||
// hack to get the default mouse interrupt handler to do what
|
||||
// we want on the //c to detect the VBL but it works for now.
|
||||
mouse_show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +56,12 @@ void shutdownMouse(void)
|
||||
}
|
||||
|
||||
|
||||
bool hasMouse(void)
|
||||
{
|
||||
return gMouseInstalled;
|
||||
}
|
||||
|
||||
|
||||
bool pollMouse(void)
|
||||
{
|
||||
static uint16_t mouseDownAtX = 0;
|
||||
|
||||
@@ -27,6 +27,7 @@ typedef struct tMouseCallbacks {
|
||||
|
||||
extern bool initMouse(tMouseCallbacks *callbacks);
|
||||
extern void shutdownMouse(void);
|
||||
extern bool hasMouse(void);
|
||||
extern bool pollMouse(void);
|
||||
extern void moveMouseToSquare(tSquare square);
|
||||
|
||||
|
||||
+18
-20
@@ -185,6 +185,7 @@ static uint8_t gSpeakIncredible[] = {
|
||||
|
||||
|
||||
static bool gSoundEnabled = false;
|
||||
static bool gMockingBoardInitialized = false;
|
||||
static bool gMockingBoardEnabled = false;
|
||||
static bool gMockingBoardSpeechEnabled = false;
|
||||
|
||||
@@ -194,35 +195,30 @@ static tMockingBoardSpeaker gMockingBoardSoundSpeaker = SPEAKER_BOTH;
|
||||
// Implementation
|
||||
|
||||
|
||||
void soundInit(tSlot mockingBoardSlot, bool enableSpeechChip)
|
||||
void soundInit(bool enableSounds, bool enableMockingBoard, bool enableSpeechChip)
|
||||
{
|
||||
gSoundEnabled = true;
|
||||
if (mockingBoardSlot > 0) {
|
||||
mockingBoardInit(mockingBoardSlot, enableSpeechChip);
|
||||
gMockingBoardEnabled = true;
|
||||
gMockingBoardSpeechEnabled = enableSpeechChip;
|
||||
// When the speech chip is on, sound effects go out the right speaker
|
||||
// only and the left speaker is used for speech. If the speech chip is
|
||||
// off, then sound effects go to both speakers.
|
||||
if (enableSpeechChip) {
|
||||
gMockingBoardSoundSpeaker = SPEAKER_RIGHT;
|
||||
} else {
|
||||
gMockingBoardSoundSpeaker = SPEAKER_BOTH;
|
||||
}
|
||||
gMockingBoardInitialized = mockingBoardInit();
|
||||
gSoundEnabled = enableSounds;
|
||||
|
||||
gMockingBoardEnabled = ((gSoundEnabled) && (gMockingBoardInitialized) && (enableMockingBoard));
|
||||
gMockingBoardSpeechEnabled = ((enableSpeechChip) && (gMockingBoardEnabled) && (mockingBoardHasSpeechChip()));
|
||||
|
||||
// When the speech chip is on, sound effects go out the right speaker
|
||||
// only and the left speaker is used for speech. If the speech chip is
|
||||
// off, then sound effects go to both speakers.
|
||||
if (gMockingBoardSpeechEnabled) {
|
||||
gMockingBoardSoundSpeaker = SPEAKER_RIGHT;
|
||||
} else {
|
||||
if (gMockingBoardEnabled) {
|
||||
mockingBoardShutdown();
|
||||
}
|
||||
gMockingBoardEnabled = false;
|
||||
gMockingBoardSpeechEnabled = false;
|
||||
gMockingBoardSoundSpeaker = SPEAKER_BOTH;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void soundShutdown(void)
|
||||
{
|
||||
if (gMockingBoardEnabled) {
|
||||
if (gMockingBoardInitialized) {
|
||||
mockingBoardShutdown();
|
||||
gMockingBoardInitialized = false;
|
||||
gMockingBoardEnabled = false;
|
||||
gMockingBoardSpeechEnabled = false;
|
||||
}
|
||||
@@ -367,6 +363,7 @@ void speakNoMoreMoves(void)
|
||||
mockingBoardSpeak(gSpeakNoMoreMoves, sizeof(gSpeakNoMoreMoves));
|
||||
}
|
||||
|
||||
|
||||
bool speakGood(void)
|
||||
{
|
||||
if (!gMockingBoardSpeechEnabled)
|
||||
@@ -392,6 +389,7 @@ bool speakExcellent(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool speakIncredible(void)
|
||||
{
|
||||
if (!gMockingBoardSpeechEnabled)
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
#include "mockingboard.h"
|
||||
|
||||
|
||||
extern void soundInit(tSlot mockingBoardSlot, bool enableSpeechChip);
|
||||
extern void soundInit(bool enableSounds, bool enableMockingBoard, bool enableSpeechChip);
|
||||
extern void soundShutdown(void);
|
||||
|
||||
extern void beginClearGemSound(void);
|
||||
|
||||
+301
-222
@@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
#include <conio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -26,24 +27,36 @@
|
||||
// Defines
|
||||
|
||||
#define SAVE_OPTIONS_FILE "A2BEJWLD.OPTS"
|
||||
#define BASE_VERSION "v2.2"
|
||||
#define VERSION "v2.7"
|
||||
|
||||
#ifdef TOTAL_REPLAY_BUILD
|
||||
#define VERSION BASE_VERSION ".tr"
|
||||
#else
|
||||
#define VERSION BASE_VERSION
|
||||
#endif
|
||||
#define OPTIONS_VERSION_UNSAVED 0
|
||||
#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 {
|
||||
bool optionsSaved;
|
||||
typedef struct tGameOptionsV2 {
|
||||
uint8_t optionsVersion;
|
||||
bool enableJoystick;
|
||||
bool enableMouse;
|
||||
bool enableSound;
|
||||
tSlot mockingBoardSlot;
|
||||
bool enableSpeechChip;
|
||||
bool enableMockingboard;
|
||||
bool enableMockingboardSpeech;
|
||||
} tGameOptionsV2;
|
||||
|
||||
typedef struct tGameOptions {
|
||||
uint8_t optionsVersion;
|
||||
uint8_t flags;
|
||||
char upChar;
|
||||
char downChar;
|
||||
char leftChar;
|
||||
char rightChar;
|
||||
} tGameOptions;
|
||||
|
||||
|
||||
@@ -107,28 +120,33 @@ static tMouseCallbacks gMouseCallbacks = {
|
||||
static bool gShouldSave = false;
|
||||
|
||||
static tGameOptions gGameOptions = {
|
||||
false, // optionsSaved
|
||||
false, // enableJoystick
|
||||
true, // enableMouse
|
||||
true, // enableSound
|
||||
0, // mockingBoardSlot
|
||||
false // enableSpeechChip
|
||||
OPTIONS_VERSION_UNSAVED, // optionsVersion
|
||||
(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++;
|
||||
}
|
||||
}
|
||||
@@ -144,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");
|
||||
}
|
||||
|
||||
@@ -161,7 +179,7 @@ static void saveOptions(void)
|
||||
FILE *optionsFile = fopen(SAVE_OPTIONS_FILE, "wb");
|
||||
|
||||
if (optionsFile != NULL) {
|
||||
gGameOptions.optionsSaved = true;
|
||||
gGameOptions.optionsVersion = OPTIONS_VERSION;
|
||||
fwrite(&gGameOptions, sizeof(gGameOptions), 1, optionsFile);
|
||||
fclose(optionsFile);
|
||||
}
|
||||
@@ -183,37 +201,67 @@ static bool loadOptions(void)
|
||||
|
||||
fclose(optionsFile);
|
||||
|
||||
// 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.
|
||||
// Overwrite it with true, forcing mockingboard sound to be on if one is detected.
|
||||
// - 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.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;
|
||||
}
|
||||
|
||||
|
||||
static void applyNewOptions(tGameOptions *newOptions)
|
||||
{
|
||||
bool oldEnableMouse = gGameOptions.enableMouse;
|
||||
|
||||
// If there is no change in game options, then nothing to do.
|
||||
if (memcmp(newOptions, &gGameOptions, sizeof(gGameOptions)) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((gGameOptions.enableSound != newOptions->enableSound) ||
|
||||
(gGameOptions.mockingBoardSlot != newOptions->mockingBoardSlot) ||
|
||||
(gGameOptions.enableSpeechChip != gGameOptions.enableSpeechChip)) {
|
||||
// If the sound parameters have changed, then re-init or shutdown sounds
|
||||
if (newOptions->enableSound) {
|
||||
soundInit(newOptions->mockingBoardSlot, newOptions->enableSpeechChip);
|
||||
} else {
|
||||
soundShutdown();
|
||||
}
|
||||
printString("\n\n\n Saving options...");
|
||||
|
||||
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->flags & OPTION_SOUND_ENABLED) != 0),
|
||||
((newOptions->flags & OPTION_MOCKINGBOARD_ENABLED) != 0),
|
||||
((newOptions->flags & OPTION_MOCKINGBOARD_SPEECH_ENABLED) !=0));
|
||||
}
|
||||
|
||||
memcpy(&gGameOptions, newOptions, sizeof(gGameOptions));
|
||||
gGameOptions.optionsSaved = false;
|
||||
if (oldEnableMouse != gGameOptions.enableMouse) {
|
||||
if (gGameOptions.enableMouse) {
|
||||
gGameOptions.enableMouse = initMouse(&gMouseCallbacks);
|
||||
}
|
||||
}
|
||||
gGameOptions.optionsVersion = OPTIONS_VERSION_UNSAVED;
|
||||
saveOptions();
|
||||
}
|
||||
|
||||
@@ -227,71 +275,119 @@ 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());
|
||||
}
|
||||
|
||||
|
||||
static bool yorn(void)
|
||||
{
|
||||
char ch;
|
||||
bool result = true;
|
||||
|
||||
showCursor();
|
||||
while (true) {
|
||||
ch = getKey();
|
||||
|
||||
if (ch == 'N') {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch == 'Y')
|
||||
break;
|
||||
|
||||
badThingHappened();
|
||||
}
|
||||
|
||||
replaceCursor(ch);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void getSoundOptions(tGameOptions *newOptions)
|
||||
{
|
||||
char ch;
|
||||
tSlot slot;
|
||||
|
||||
printString("\n\nEnable sounds? (Y/N) ");
|
||||
showCursor();
|
||||
while (true) {
|
||||
ch = cgetc();
|
||||
if ((ch == 'N') ||
|
||||
(ch == 'n')) {
|
||||
newOptions->enableSound = false;
|
||||
newOptions->mockingBoardSlot = 0;
|
||||
newOptions->enableSpeechChip = false;
|
||||
return;
|
||||
}
|
||||
if ((ch == 'Y') ||
|
||||
(ch == 'y')) {
|
||||
replaceCursor(ch);
|
||||
newOptions->enableSound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
badThingHappened();
|
||||
if (yorn()) {
|
||||
newOptions->flags |= OPTION_SOUND_ENABLED;
|
||||
} else {
|
||||
newOptions->flags &= ~OPTION_SOUND_ENABLED;
|
||||
return;
|
||||
}
|
||||
|
||||
printString("\nMockingBoard slot number (0 for none) ");
|
||||
showCursor();
|
||||
while (true) {
|
||||
ch = cgetc();
|
||||
if (ch == '0') {
|
||||
newOptions->mockingBoardSlot = 0;
|
||||
newOptions->enableSpeechChip = false;
|
||||
return;
|
||||
}
|
||||
if ((ch >= '1') &&
|
||||
(ch <= '7')) {
|
||||
replaceCursor(ch);
|
||||
newOptions->mockingBoardSlot = (ch - '0');
|
||||
break;
|
||||
}
|
||||
|
||||
badThingHappened();
|
||||
// If no mockingboard present, don't bother to ask whether to enable/disable it.
|
||||
slot = mockingBoardSlot();
|
||||
if (slot == 0)
|
||||
return;
|
||||
|
||||
printString("\nEnable MockingBoard sound found in slot ");
|
||||
printInteger(slot);
|
||||
printString("? (Y/N) ");
|
||||
if (yorn()) {
|
||||
newOptions->flags |= OPTION_MOCKINGBOARD_ENABLED;
|
||||
} else {
|
||||
newOptions->flags &= ~OPTION_MOCKINGBOARD_ENABLED;
|
||||
return;
|
||||
}
|
||||
|
||||
printString("\nMockingBoard has a speech chip? (Y/N) ");
|
||||
// If the mockingboard does not have a speech chip, do not prompt whether to
|
||||
// enable/disable it.
|
||||
if (!mockingBoardHasSpeechChip())
|
||||
return;
|
||||
|
||||
printString("\nEnable speech on the Mockingboard? (Y/N) ");
|
||||
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 = cgetc();
|
||||
if ((ch == 'N') ||
|
||||
(ch == 'n')) {
|
||||
newOptions->enableSpeechChip = false;
|
||||
ch = getKey();
|
||||
if ((isalnum(ch)) &&
|
||||
(ch != 'Q') &&
|
||||
(ch != 'R') &&
|
||||
(ch != 'O') &&
|
||||
(ch != 'H') &&
|
||||
(ch != other1) &&
|
||||
(ch != other2) &&
|
||||
(ch != other3))
|
||||
break;
|
||||
}
|
||||
if ((ch == 'Y') ||
|
||||
(ch == 'y')) {
|
||||
newOptions->enableSpeechChip = true;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -306,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
|
||||
@@ -313,30 +412,51 @@ static void selectOptions(void)
|
||||
" Apple // Bejeweled\n"
|
||||
" Options\n"
|
||||
"\n"
|
||||
" J - Joystick control - ");
|
||||
printString(newOptions.enableJoystick ? "Enable\n" : "Disabled\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.flags & OPTION_JOYSTICK_ENABLED) != 0) ? "Enabled\n" : "Disabled\n");
|
||||
if (hasMouse())
|
||||
{
|
||||
printString(
|
||||
" M - Mouse control - ");
|
||||
printString(newOptions.enableMouse ? "Enable\n" : "Disabled\n");
|
||||
printString(((newOptions.flags & OPTION_MOUSE_ENABLED) != 0) ? "Enabled\n" : "Disabled\n");
|
||||
}
|
||||
printString(
|
||||
" S - Sound - ");
|
||||
printString(newOptions.enableSound ? "Enable\n" : "Disabled\n");
|
||||
printString(enableSound ? "Enabled\n" : "Disabled\n");
|
||||
|
||||
if (newOptions.enableSound) {
|
||||
if (newOptions.mockingBoardSlot > 0) {
|
||||
if (enableSound) {
|
||||
tSlot slot = mockingBoardSlot();
|
||||
|
||||
if (slot != 0) {
|
||||
printString(
|
||||
// 0000000001111111111222222222233333333334444444444555555555566666666667
|
||||
// 1234567890123456789012345678901234567890123456789012345678901234567890
|
||||
" MockingBoard - Slot ");
|
||||
printInteger(newOptions.mockingBoardSlot);
|
||||
printString("\n"
|
||||
" Speech Chip - ");
|
||||
printString(newOptions.enableSpeechChip ? "Enable\n" : "Disable\n");
|
||||
} else {
|
||||
printString(
|
||||
// 0000000001111111111222222222233333333334444444444555555555566666666667
|
||||
// 1234567890123456789012345678901234567890123456789012345678901234567890
|
||||
" MockingBoard - Disabled\n");
|
||||
" MockingBoard - ");
|
||||
printString(enableMockingboard ? "Enabled (Slot " : "Disabled (Slot ");
|
||||
printInteger(slot);
|
||||
printString(")\n");
|
||||
|
||||
if ((enableMockingboard) &&
|
||||
(mockingBoardHasSpeechChip()))
|
||||
{
|
||||
printString(
|
||||
// 0000000001111111111222222222233333333334444444444555555555566666666667
|
||||
// 1234567890123456789012345678901234567890123456789012345678901234567890
|
||||
" Speech - ");
|
||||
printString(((newOptions.flags & OPTION_MOCKINGBOARD_SPEECH_ENABLED) != 0) ? "Enabled\n" : "Disabled\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
printString(
|
||||
@@ -346,28 +466,26 @@ 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;
|
||||
if (newOptions.enableJoystick) {
|
||||
newOptions.enableMouse = false;
|
||||
}
|
||||
newOptions.flags ^= OPTION_JOYSTICK_ENABLED;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
newOptions.enableMouse = !newOptions.enableMouse;
|
||||
if (newOptions.enableMouse) {
|
||||
newOptions.enableJoystick = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
case 'S':
|
||||
getSoundOptions(&newOptions);
|
||||
break;
|
||||
|
||||
case 'K':
|
||||
getKeyboardOptions(&newOptions);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
if (hasMouse()) {
|
||||
newOptions.flags ^= OPTION_MOUSE_ENABLED;
|
||||
break;
|
||||
}
|
||||
// Fall through. If no mouse, then pressing m is a fall through into the save code.
|
||||
|
||||
default:
|
||||
applyNewOptions(&newOptions);
|
||||
clrscr();
|
||||
@@ -390,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"
|
||||
@@ -418,8 +547,7 @@ void printInstructions(void)
|
||||
|
||||
srand(seed);
|
||||
|
||||
switch (cgetc()) {
|
||||
case 'o':
|
||||
switch (getKey()) {
|
||||
case 'O':
|
||||
selectOptions();
|
||||
break;
|
||||
@@ -607,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;
|
||||
@@ -630,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();
|
||||
@@ -710,32 +829,22 @@ static void getHint(void)
|
||||
void initUI(void)
|
||||
{
|
||||
bool optionsLoaded;
|
||||
bool mouseInitialized;
|
||||
|
||||
initMachine();
|
||||
|
||||
optionsLoaded = loadOptions();
|
||||
|
||||
initGameEngine(&gCallbacks);
|
||||
mouseInitialized = initMouse(&gMouseCallbacks);
|
||||
soundInit(((gGameOptions.flags & OPTION_SOUND_ENABLED) != 0),
|
||||
((gGameOptions.flags & OPTION_MOCKINGBOARD_ENABLED) != 0),
|
||||
((gGameOptions.flags & OPTION_MOCKINGBOARD_SPEECH_ENABLED) != 0));
|
||||
|
||||
// If we couldn't initialize a mouse and it was enabled on the options, then disable it.
|
||||
if ((!mouseInitialized) &&
|
||||
(gGameOptions.enableMouse)) {
|
||||
gGameOptions.enableMouse = false;
|
||||
gGameOptions.optionsSaved = false;
|
||||
}
|
||||
initGameEngine(&gCallbacks);
|
||||
|
||||
initMouse(&gMouseCallbacks);
|
||||
|
||||
initJoystick(&gJoyCallbacks);
|
||||
|
||||
if (gGameOptions.enableSound) {
|
||||
if (!optionsLoaded) {
|
||||
gGameOptions.mockingBoardSlot = getMockingBoardSlot();
|
||||
}
|
||||
soundInit(gGameOptions.mockingBoardSlot, gGameOptions.enableSpeechChip);
|
||||
}
|
||||
|
||||
if (!gGameOptions.optionsSaved) {
|
||||
if (gGameOptions.optionsVersion == OPTIONS_VERSION_UNSAVED) {
|
||||
saveOptions();
|
||||
}
|
||||
}
|
||||
@@ -799,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);
|
||||
@@ -828,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);
|
||||
@@ -847,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);
|
||||
@@ -911,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;
|
||||
@@ -957,33 +1055,14 @@ void playGame(void)
|
||||
printString("\n\nChecking for a saved game...");
|
||||
|
||||
if (loadGame()) {
|
||||
bool gotAnswer = false;
|
||||
bool loadSavedGame = false;
|
||||
|
||||
printString("\n\nYou have a saved game!\n Would you like to continue it (Y/N) ");
|
||||
|
||||
showCursor();
|
||||
while (!gotAnswer) {
|
||||
ch = cgetc();
|
||||
switch (ch) {
|
||||
case 'y':
|
||||
case 'Y':
|
||||
replaceCursor(ch);
|
||||
printString("\n\nLoading your saved puzzle");
|
||||
gotAnswer = true;
|
||||
gShouldSave = true;
|
||||
gameLoaded = true;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
replaceCursor(ch);
|
||||
gotAnswer = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
badThingHappened();
|
||||
break;
|
||||
}
|
||||
loadSavedGame = yorn();
|
||||
if (loadSavedGame) {
|
||||
printString("\n\nLoading your saved puzzle");
|
||||
gShouldSave = true;
|
||||
gameLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -994,6 +1073,14 @@ void playGame(void)
|
||||
drawBoard();
|
||||
speakGo();
|
||||
while (true) {
|
||||
if (gameIsOver()) {
|
||||
endGame();
|
||||
showAndClearDblLoRes();
|
||||
refreshScore(0);
|
||||
startNewGame();
|
||||
gShouldSave = false;
|
||||
}
|
||||
|
||||
resetStarAnim();
|
||||
|
||||
while (true) {
|
||||
@@ -1003,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user