aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <yalhcru@gmail.com>2021-04-04 03:35:22 -0400
committerB. Watson <yalhcru@gmail.com>2021-04-04 03:35:22 -0400
commit5ef86baf365b9c7e80fdc1df1283937698db37a5 (patch)
treec259f2642e4ba6b5c9feed211eedc79063a237b9
parent30a7443be9ca61eeee3f2a2128b12598f2f3fc70 (diff)
downloadtaipan-5ef86baf365b9c7e80fdc1df1283937698db37a5.tar.gz
Inline some array code, 8128 bytes free
-rw-r--r--GAMEPLAY.txt34
-rw-r--r--Makefile2
-rw-r--r--NOTES.txt20
-rw-r--r--arrayutils.s60
-rw-r--r--taipan.c34
-rw-r--r--timed_getch.s13
6 files changed, 122 insertions, 41 deletions
diff --git a/GAMEPLAY.txt b/GAMEPLAY.txt
index ab937ee..74d39c9 100644
--- a/GAMEPLAY.txt
+++ b/GAMEPLAY.txt
@@ -43,18 +43,6 @@ You also might get attacked by pirates. If this happens, you enter the
combat phase of the turn. Otherwise, you'll arrive in port and begin
your next turn.
-During combat, you have three choices: Fight, Run, or Throw Cargo. If
-your ship doesn't have any guns, don't bother trying to fight. Running
-away is always an option, but the enemy will chase you, so you can't
-always escape right away. Throw Cargo means you have your crew throw
-some of your cargo into the water, in hopes that it will distract the
-pirates or satisfy their greed, allowing you to get away safely.
-
-When the battle first starts, you choose between Fight, Run, or Throw
-Cargo. During the fight, you can change your orders at any time by
-pressing the key for the new order (F, R, or T).
-
-
Details
-------
@@ -85,7 +73,7 @@ The next screen offers you the choice of starting with either:
2 - 5 guns, no cash, and no debt.
Your ship has a cargo capacity of 60 units either way, but each gun
-takes up 10 units so option 2 gives you only 10 units for carrying
+takes up 10 units, so option 2 gives you only 10 units for carrying
cargo. Later in the game, you'll get the options to buy guns and
upgrade your ship to higher capacity.
@@ -126,3 +114,23 @@ Opium - A highly addictive drug, but not without medical uses. It's
risky to trade in opium becase it's illegal in most ports. However,
the potential gains may be worth the risk.
+Combat
+------
+
+During combat, you have three choices: Fight, Run, or Throw Cargo. If
+your ship doesn't have any guns, don't bother trying to fight. Running
+away is always an option, but the enemy will chase you, so you can't
+always escape right away. Throw Cargo means you have your crew throw
+some of your cargo into the water, in hopes that it will distract the
+pirates or satisfy their greed, allowing you to get away safely.
+
+When the battle first starts, you choose between Fight, Run, or Throw
+Cargo. During the fight, you can change your orders at any time by
+pressing the key for the new order (f, r, or t).
+
+If you get impatient during combat, you can use "Turbo" mode:
+hold Shift when you press F or R (Fight or Run). This disables the
+animations and delays, so each combat round happens very quickly. If
+the fight starts going badly, you can press any key to exit Turbo mode
+and return to normal speed.
+
diff --git a/Makefile b/Makefile
index 1176b96..5d83419 100644
--- a/Makefile
+++ b/Makefile
@@ -106,7 +106,7 @@ XEX=taipan.xex
# All the C and asm sources for taimain.xex:
TAIMAIN_HDRS=sounds.h
TAIMAIN_C_SRC=taipan.c strtonum.c
-TAIMAIN_ASM_SRC=rand.s draw_lorcha.s timed_getch.s portstat.s console.s cprintul.s soundasm.s explosion.s textdecomp.s
+TAIMAIN_ASM_SRC=rand.s draw_lorcha.s timed_getch.s portstat.s console.s cprintul.s soundasm.s explosion.s textdecomp.s arrayutils.s
TAIMAIN_LIBS=conio/conio.lib
# Comment these lines out to build without big number support.
diff --git a/NOTES.txt b/NOTES.txt
index 6825336..ac7eb33 100644
--- a/NOTES.txt
+++ b/NOTES.txt
@@ -23,38 +23,40 @@ arcade game).
Deliberate differences between the Apple II and Atari ports:
-0. The Atari version is noticeably faster than the Apple version on II+ or
+0. Turbo mode, in combat. See MANUAL.txt.
+
+1. The Atari version is noticeably faster than the Apple version on II+ or
IIe. This is because it's written in C and assembly, not interpreted
BASIC. A IIgs on the other hand...
-1. "Press ESC for help" rather than ESC to start. Starting the game is
+2. "Press ESC for help" rather than ESC to start. Starting the game is
done with the space bar or return key.
-2. I made it possible to disable the sound, since it's kinda repetitive
+3. I made it possible to disable the sound, since it's kinda repetitive
and annoying, plus the game "freezes" while sounds are playing (no
threading on Atari!) which slows down gameplay.
-3. Added a way to change the background color and text brightness. Only
+4. Added a way to change the background color and text brightness. Only
4 brightness levels, but all 16 Atari hues are available.
-4. Prompts that only accept one character no longer require pressing Enter.
+5. Prompts that only accept one character no longer require pressing Enter.
Gameplay is more streamlined this way. Apple and Linux are inconsistent:
some prompts need Enter, some don't. In the Atari port, the only prompts
that require Enter are:
- naming your firm
- entering an amount of cash or items (but not if you hit A for "all")
-5. "We have 5 guns" is in an inverse video box. I think it looks nicer, and
+6. "We have 5 guns" is in an inverse video box. I think it looks nicer, and
it matches the "You can afford 5" inverse video box on the trading
screen.
-6. The + that indicates more ships offscreen is inverse video. I find
+7. The + that indicates more ships offscreen is inverse video. I find
that I don't notice it's there, if it's normal video.
-7. "You're ship is overloaded" => "Your ship is overloaded". Sorry,
+8. "You're ship is overloaded" => "Your ship is overloaded". Sorry,
grammar nazi.
-8. Updating the port status screen, and text printing in general, happens
+9. Updating the port status screen, and text printing in general, happens
faster and cleaner-looking, due to using C and asm rather than BASIC,
and also because the static parts of the screen aren't redrawn unless
they need to be. (Grammar nazi? That's a run-on sentence...)
diff --git a/arrayutils.s b/arrayutils.s
new file mode 100644
index 0000000..188ace4
--- /dev/null
+++ b/arrayutils.s
@@ -0,0 +1,60 @@
+; extern void clear_ships_on_screen(void);
+
+; optimized bzero() replacement.
+; the real bzero() in cc65-2.19 is 129 bytes long.
+; it's optimized for speed (has an unrolled loop) and shares
+; code with memset(). we can do it in a lot less code here,
+; especially since we only need to clear exactly 20 bytes
+; located at a known absolute address.
+
+; in C, we could write: for(i=0; i<len; i++) { arr[i] = 0; }
+; ...which takes up around 64 bytes of code.
+; instead, this: clear_ships_on_screen();
+; ...takes 3 bytes for the function call, plus ~20 bytes for
+; the function, or around 1/3 the size of the for loop, or under 1/4
+; the size of bzero() plus its function call.
+
+ .import _ships_on_screen
+ .export _have_ships_on_screen, _clear_ships_on_screen
+
+ .include "atari.inc"
+
+ .proc _clear_ships_on_screen
+ ldx #$14
+ lda #0
+@l:
+ sta _ships_on_screen-1,x
+ dex
+ bne @l
+ rts
+ .endproc
+
+; extern char have_ships_on_screen(void);
+
+; optimized (both size and speed) replacement for:
+
+; if ((ships_on_screen[0] == 0) && (ships_on_screen[1] == 0) &&
+; (ships_on_screen[2] == 0) && (ships_on_screen[3] == 0) &&
+; (ships_on_screen[4] == 0) && (ships_on_screen[5] == 0) &&
+; (ships_on_screen[6] == 0) && (ships_on_screen[7] == 0) &&
+; (ships_on_screen[8] == 0) && (ships_on_screen[9] == 0))
+
+; ...which compiles to ~100 bytes of code. a for loop would be
+; around 64 bytes (like the clearing loop above). this is 3 bytes
+; for the function call plus 11 bytes for the function, plus a
+; couple more bytes for the ! in front of the function call (since
+; the result is opposite what the original code did).
+; I could save the 3 bytes by inlining this as asm() in the C code,
+; but it would be more fragile than making a separate function.
+
+ .proc _have_ships_on_screen
+ ldx #$14 ; sizeof(ships_on_screen)
+@l:
+ lda _ships_on_screen-1,x
+ bne @done ; found a non-0 byte, A and X are both non-zero
+ dex
+ bne @l
+ ; end of loop. if we get here, A and X are both zero
+@done:
+ rts
+ .endproc
diff --git a/taipan.c b/taipan.c
index 65a017a..e987170 100644
--- a/taipan.c
+++ b/taipan.c
@@ -75,6 +75,9 @@ extern unsigned char __fastcall__ yngetc(char dflt);
/* sleep for j jiffies (no PAL adjustment at the moment) */
extern void __fastcall__ jsleep(unsigned int j);
+/* sleep for j jiffies unless turbo is true */
+extern void __fastcall__ tjsleep(unsigned int j);
+
/* flash screen when we're hit in combat */
extern void explosion(void);
@@ -1012,10 +1015,13 @@ void set_orders(void) {
/* sea_battle only ever returns 1 to 4. making the
return type a char saved 61 bytes! */
+int ships_on_screen[10];
+extern char have_ships_on_screen(void);
+extern void clear_ships_on_screen(void);
+
char sea_battle(char id, int num_ships) {
/* These locals seem to eat too much stack and
cause weird behaviour, so they're static now. */
- static int ships_on_screen[10];
static int time,
s0,
ok,
@@ -1025,15 +1031,16 @@ char sea_battle(char id, int num_ships) {
char choice, flashctr, num_on_screen, status;
unsigned long amount, total;
- turbo = 0;
port_stat_dirty = 1;
+ ik = 1;
+ ok = 0;
+ turbo = 0;
orders = 0;
num_on_screen = 0;
+
time = get_time();
s0 = num_ships;
- ok = 0;
- ik = 1;
booty = (time / 4 * 1000 * num_ships) + randi()%1000 + 250;
if(would_overflow(cash, booty)) {
@@ -1088,7 +1095,7 @@ char sea_battle(char id, int num_ships) {
for(i = 0; i <= 9; i++) {
if (num_ships > num_on_screen) {
if (ships_on_screen[i] == 0) {
- if(!turbo) jsleep(5);
+ tjsleep(5);
ships_on_screen[i] = (randi() % ec) + 20;
draw_lorcha(i);
num_on_screen++;
@@ -1146,12 +1153,7 @@ char sea_battle(char id, int num_ships) {
set_orders();
for(i = 1; i <= guns; i++) {
- if ((ships_on_screen[0] == 0) && (ships_on_screen[1] == 0) &&
- (ships_on_screen[2] == 0) && (ships_on_screen[3] == 0) &&
- (ships_on_screen[4] == 0) && (ships_on_screen[5] == 0) &&
- (ships_on_screen[6] == 0) && (ships_on_screen[7] == 0) &&
- (ships_on_screen[8] == 0) && (ships_on_screen[9] == 0))
- {
+ if(!have_ships_on_screen()) {
static int j;
for (j = 0; j <= 9; j++) {
@@ -1176,9 +1178,9 @@ char sea_battle(char id, int num_ships) {
/* flash_lorcha must be called an even number of times
to leave the lorcha in an unflashed state after. */
- if(!turbo) for(flashctr = 0; flashctr < 6; flashctr++) {
+ for(flashctr = 0; flashctr < 6; flashctr++) {
flash_lorcha(targeted);
- jsleep(2);
+ tjsleep(2);
}
damage_lorcha(targeted);
@@ -1205,7 +1207,7 @@ char sea_battle(char id, int num_ships) {
if(num_ships == 0) {
i += guns;
} else {
- if(!turbo) jsleep(10);
+ tjsleep(10);
}
}
gotox0y(3);
@@ -1248,7 +1250,7 @@ char sea_battle(char id, int num_ships) {
num_on_screen--;
clear_lorcha(i);
- if(!turbo) jsleep(5);
+ tjsleep(5);
}
}
if(num_ships == num_on_screen) {
@@ -1419,7 +1421,7 @@ char sea_battle(char id, int num_ships) {
num_on_screen--;
clear_lorcha(i);
- jsleep(5);
+ tjsleep(5);
}
}
plus_or_space(num_ships > num_on_screen);
diff --git a/timed_getch.s b/timed_getch.s
index eaf7ab3..5c5ff7c 100644
--- a/timed_getch.s
+++ b/timed_getch.s
@@ -1,7 +1,7 @@
.export _timed_getch, _set_jiffy_timer, _agetc, _numgetc
- .export _yngetc, _lcgetc, _jsleep, _get_item
- .import _cgetc, _cblank, putchar, _rand
+ .export _yngetc, _lcgetc, _jsleep, _get_item, _tjsleep
+ .import _cgetc, _cblank, putchar, _rand, _turbo
.include "atari.inc"
@@ -13,6 +13,14 @@
; keyboard and timer functions for taipan.
+; sleep for j jiffies, unless _turbo is set.
+; extern void __fastcall__ tjsleep(unsigned int j);
+_tjsleep:
+ sta FR0+4
+ lda _turbo
+ bne jret
+ lda FR0+4
+
; sleep for j jiffies.
; extern void __fastcall__ jsleep(unsigned int j);
_jsleep:
@@ -21,6 +29,7 @@ jiffy_wait:
lda CDTMV3
ora CDTMV3+1
bne jiffy_wait
+jret:
rts
; extern void __fastcall__ set_jiffy_timer(unsigned int jiffies);