aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile31
-rw-r--r--PORTSTAT.DATbin0 -> 640 bytes
-rw-r--r--README.txt51
-rw-r--r--mkportstats.c55
-rw-r--r--portstat.s9
-rw-r--r--rand.s1
-rw-r--r--taipan.c144
7 files changed, 225 insertions, 66 deletions
diff --git a/Makefile b/Makefile
index 6eed257..4daa2ea 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,29 @@
CC=cl65
SYS=atari
-# COPT=-Oirs
-COPT=-O -l -T
-CFLAGS=-t $(SYS) -C custom.cfg -I. -L. $(COPT)
+
+# the meaning of the -l flag is different between cc65-2.13.3
+# and the later github cc65, so it's commented out here.
+#COPT=-O -l -T
+COPT=-O -T
+
+# for older cc65:
+#CFLAGS=-t $(SYS) -C custom.cfg -I. -L. $(COPT)
+
+# for recent git cc65.
+# -D__RESERVED_MEMORY__=1056 because cc65's default end of memory
+# is $BC20, and we want it to end just below our font, which starts
+# at $B800.
+# -D__SYSTEM_CHECK__=1 stops cl65 from prepending a bit of code that
+# checks to make sure there's enough memory. Older cc65 didn't do this,
+# and I never missed it.
+CFLAGS=-t $(SYS) -I. -L. -Wl -D__SYSTEM_CHECK__=1 -Wl -D__RESERVED_MEMORY__=1056 $(COPT)
AS=ca65
-ASFLAGS=-l
+ASFLAGS=
AR=ar65
+VERSION="v0.99alpha-$(shell date +%Y%m%d)-$(shell git rev-parse --short HEAD 2>/dev/null || echo UNKNOWN)"
+
# A few files have no make rules here. LORCHA.DAT is generated as a
# side-effect of generating taifont.xex. It's a 49-byte (7x7) blob of
# Atari "internal" screen codes.
@@ -28,6 +44,9 @@ XEX=taipan.xex
all: $(XEX)
+ver:
+ @echo $(VERSION)
+
$(XEX): taimain.xex taifont.xex title.xex
cat taifont.xex title.xex taimain.xex > $(XEX)
@@ -35,7 +54,7 @@ title.xex: TITLE.DAT
perl title.pl TITLE.DAT > title.xex
taimain.xex: taipan.c rand.s draw_lorcha.s taifont.xex
- cl65 --mapfile taipan.map -t atari -O -l -T -o taimain.xex taipan.c rand.s draw_lorcha.s timed_getch.s jsleep.s
+ cl65 -DVERSION=\"$(VERSION)\" --mapfile taipan.map $(CFLAGS) -o taimain.xex taipan.c rand.s draw_lorcha.s timed_getch.s jsleep.s portstat.s
taifont.xex: convfont romfont font
cat romfont font | ./convfont -x > taifont.xex
@@ -66,6 +85,6 @@ distclean: clean
$(CC) --mapfile map $(CFLAGS) -o $@ $<
lorchatest: lorchatest.c draw_lorcha.s taifont.xex
- cl65 -t atari -O -l -T -o lorchatest1.xex lorchatest.c draw_lorcha.s
+ cl65 -t atari -O -T -o lorchatest1.xex lorchatest.c draw_lorcha.s
cat taifont.xex lorchatest1.xex > lorchatest.xex
atari800 -nobasic lorchatest.xex
diff --git a/PORTSTAT.DAT b/PORTSTAT.DAT
new file mode 100644
index 0000000..0af616c
--- /dev/null
+++ b/PORTSTAT.DAT
Binary files differ
diff --git a/README.txt b/README.txt
index b31622b..b65a535 100644
--- a/README.txt
+++ b/README.txt
@@ -7,6 +7,15 @@ II version.
Currently the game is playable but incomplete, and has a few known bugs
(see "Bugs" section below) and probably a few unknown ones too.
+The latest version of the source can be found here:
+http://urchlay.naptime.net/repos/taipan/
+
+A binary of the game can be found here:
+
+http://urchlay.naptime.net/~urchlay/src/taipan.xex
+
+...though it might be outdated.
+
Linux/curses port can be found here:
http://www.ibiblio.org/pub/linux/games/textrpg/
@@ -22,11 +31,11 @@ What's missing:
- Large integer (or floating point) support. Cash, Bank, and Debt
amounts will roll over to 0 if they exceed the max value for a 32-bit
unsigned integer (around 4 billion). I'm not sure if this is a real
- problem for anyone (it takes a *long* time to get over a billion in
- this game).
+ problem for anyone (it takes a *long* time to get over a billion
+ in this game). As a side effect of this, the "negative interest"
+ bug/feature is missing.
-- The title screen and ship graphics are pretty crude compared to
- the Apple II original (though they're nicer than the curses ones).
+- The title screen isn't as nice as the Apple version.
Building:
@@ -34,6 +43,19 @@ Prerequisites are GNU make, cc65 (I use version 2.13.0, any recent one
should do), perl (any recent-ish version), and a *nix-like environment (I
use Slackware Linux, if you're on Windows you might try Cygwin or Msys).
+Build Requirements:
+
+- GNU make. I use version 3.82, but I don't use any of its special
+ features, so any version should do. In fact, BSD make might work.
+
+- cc65. Originally I used version 2.13.3, and part way through I
+ upgraded to a git snapshot dated December 29, 2015.
+
+- perl. I use version 5.18.1, probably any 5.x version will work.
+
+- A UNIX/POSIX environment. At least, you need a 'cat' command and
+ a shell that does I/O redirection.
+
If you plan to edit the title screen or ship graphics, you'll need
the Atari800 emulator. It's also handy for actually playing the game,
whether you build it or use the provided binary.
@@ -41,15 +63,18 @@ whether you build it or use the provided binary.
Running:
The game binary is called "taipan.xex". It's a standard Atari DOS
-'binary load' file. You can load it on a real Atari computer: any
-400/800/XL/XE model should be fine, so long as it has at least 48K of
-RAM. Use a SIO2PC cable and software like Atariserver (Linux) or APE
-(Windows) to download the game to the Atari. If you can come up with
-a way to actually copy it to a real floppy disk, you probably want a
-bootable DOS disk with Taipan renamed to AUTORUN.SYS.
-
-It's also possible to run Taipan in an emulator, such as Atari800
-or Altirra.
+'binary load' file, which expects to be run with BASIC disabled and no
+cartridges inserted.
+
+You can run it on a real Atari computer: any 400/800/XL/XE model should
+be fine, so long as it has at least 48K of RAM. Use a SIO2PC cable and
+software like Atariserver (Linux) or APE (Windows) to serve the game to
+the Atari. If you can come up with a way to actually copy it to a real
+floppy disk, you probably want a bootable DOS disk with Taipan renamed
+to AUTORUN.SYS.
+
+It's also possible to run Taipan in an emulator, such as Atari800,
+Atari++, or Altirra.
License:
diff --git a/mkportstats.c b/mkportstats.c
new file mode 100644
index 0000000..0d4d374
--- /dev/null
+++ b/mkportstats.c
@@ -0,0 +1,55 @@
+#include <conio.h>
+#include <stdio.h>
+#include <peekpoke.h>
+
+void port_stats() {
+ cursor(0);
+ clrscr();
+ chlinexy(1, 1, 26);
+ chlinexy(1, 7, 26);
+ chlinexy(1, 13, 26);
+ cvlinexy(0, 2, 5);
+ cvlinexy(27, 2, 5);
+ cvlinexy(0, 8, 5);
+ cvlinexy(27, 8, 5);
+ chlinexy(0, 15, 40);
+
+ cputcxy(0, 1, 17); // upper left corner
+ cputcxy(0, 7, 1); // |-
+ cputcxy(0, 13, 26); // lower left corner
+
+ cputcxy(27, 1, 5); // upper right corner
+ cputcxy(27, 7, 4); // -|
+ cputcxy(27, 13, 3); // lower right corner
+
+ cputsxy(1, 2, "Hong Kong Warehouse");
+ cputsxy(4, 3, "Opium In use");
+ cputsxy(4, 4, "Silk ");
+ cputsxy(4, 5, "Arms Vacant");
+ cputsxy(4, 6, "General ");
+ cputsxy(1, 8, "Hold ");
+ cputsxy(16, 8, "Guns ");
+
+ cputsxy(4, 9, "Opium ");
+ cputsxy(4, 10, "Silk ");
+ cputsxy(4, 11, "Arms ");
+ cputsxy(4, 12, "General ");
+ cputsxy(32, 2, "Date");
+ cputsxy(29, 3, "15 ");
+
+ cputsxy(30, 5, "Location");
+ cputsxy(32, 8, "Debt");
+ cputsxy(29, 11, "Ship Status");
+ cputsxy(0, 14, "Cash: ");
+ cputsxy(20, 14, "Bank: ");
+}
+
+int main(void) {
+ char *screenmem = PEEK(88)+256*PEEK(89);
+ FILE *f = fopen("H:PORTSTAT.DAT", "wb");
+ port_stats();
+ fwrite(screenmem, 40, 16, f);
+ fclose(f);
+ cgetc();
+ return 0;
+}
diff --git a/portstat.s b/portstat.s
new file mode 100644
index 0000000..2f0d075
--- /dev/null
+++ b/portstat.s
@@ -0,0 +1,9 @@
+
+ .export _port_stat_screen
+
+; PORTSTAT.DAT is created on the H: device by running mkportstats.xex
+; in atari800. H: needs to be set writable and pointed to the current
+; directory.
+
+_port_stat_screen:
+ .incbin "PORTSTAT.DAT"
diff --git a/rand.s b/rand.s
index 3d64c74..1fa7d8d 100644
--- a/rand.s
+++ b/rand.s
@@ -17,7 +17,6 @@ _randi:
; void __fastcall__ randl(void);
_randl:
lda RANDOM
-randl1:
sta sreg
lda RANDOM
sta sreg+1
diff --git a/taipan.c b/taipan.c
index 40cfb5d..334543e 100644
--- a/taipan.c
+++ b/taipan.c
@@ -8,7 +8,10 @@
/* define this for testing sea_battle(). it causes a pirate
attack every time you leave port. Don't leave defined for
a release!! */
-#define COMBAT_TEST
+// #define COMBAT_TEST
+
+/* define this to show internals of damage calculation */
+#define DAMAGE_TEST
/**** atari-specific stuff */
@@ -58,6 +61,7 @@ unsigned long randl() {
}
*/
+extern const char *port_stat_screen;
/**** End of atari-specific stuff */
@@ -179,6 +183,8 @@ int hold = 0,
wu_warn = 0,
wu_bailout = 0;
+int newdamage;
+
/* print an int or long as a string, conio-style */
void cprintulong(unsigned long ul) {
cputs(ultoa(ul, fancy_num, 10));
@@ -312,7 +318,7 @@ void new_gun(void)
fancy_numbers(amount, fancy_num);
compradores_report();
- cputs("Do you wish to buy a ship's gun\r\n for ");
+ cputs("Do you wish to buy a ship's gun\r\nfor ");
cputs(fancy_num);
cputs(", Taipan? ");
@@ -963,7 +969,24 @@ int sea_battle(int id, int num_ships) {
// damage = damage + randclamp((ed * i * id)/2) + (i / 2);
// damage = damage + randclamp((ed * i * id)/2) + (i / 2); // b0rked
- damage = damage + (randi() % ((ed * i * id)/2)) + (i / 2);
+ newdamage = (randi() % ((ed * i * id)/2)) + (i / 2);
+ // damage = damage + (randi() % ((ed * i * id)/2)) + (i / 2);
+ damage += newdamage;
+
+#ifdef DAMAGE_TEST
+ gotoxy(0, 23);
+ cprintulong(ed);
+ cputc(' ');
+ cprintulong(i);
+ cputc(' ');
+ cprintulong(id);
+ cputc(' ');
+ cprintulong(damage);
+ cputc(' ');
+ cprintulong(newdamage);
+ cgetc();
+#endif
+
if(damage > capacity) damage = capacity; /* just in case */
if((id == GENERIC) && (randi()%20 == 0)) {
return 2;
@@ -1127,13 +1150,13 @@ void port_stats(void)
int i, in_use,
status = 100 - ((damage * 100) / capacity);
- clrscr();
- gotox(12 - strlen(firm) / 2); /* TODO: store in global */
- cputs("Firm: ");
- cputs(firm);
- cputs(", Hong Kong");
+ /* all the static text that used to be in port_stats() has
+ been moved to mkportstats.c, which creates a .xex file which
+ will get prepended to taipan.xex and loaded into a chunk of memory
+ cc65 won't use. When it's time to print it, it'll get memcpy()ed
+ into *SAVMSC. */
- show_damage();
+#if 0
chlinexy(1, 1, 26);
chlinexy(1, 7, 26);
chlinexy(1, 13, 26);
@@ -1154,34 +1177,57 @@ void port_stats(void)
cputsxy(1, 2, "Hong Kong Warehouse");
cputsxy(4, 3, "Opium In use");
cputsxy(4, 4, "Silk ");
- in_use = hkw_[0] + hkw_[1] + hkw_[2] + hkw_[3];
- // printw("%d", in_use);
- cprintulong(in_use);
cputsxy(4, 5, "Arms Vacant");
cputsxy(4, 6, "General ");
- // printw("%d", (10000 - in_use));
+ cputsxy(1, 8, "Hold ");
+ cputsxy(16, 8, "Guns ");
+
+ cputsxy(4, 9, "Opium ");
+ cputsxy(4, 10, "Silk ");
+ cputsxy(4, 11, "Arms ");
+ cputsxy(4, 12, "General ");
+ cputsxy(32, 2, "Date");
+ cputsxy(29, 3, "15 ");
+
+ cputsxy(30, 5, "Location");
+ cputsxy(32, 8, "Debt");
+ cputsxy(29, 11, "Ship Status");
+ cputsxy(0, 14, "Cash: ");
+ cputsxy(20, 14, "Bank: ");
+#else
+
+ void *p = PEEK(88) + 256 * PEEK(89);
+ memcpy(p, &port_stat_screen, 640);
+#endif
+
+ /* dynamic stuff: */
+ gotoxy(12 - strlen(firm) / 2, 0); /* TODO: store in global */
+ cputs("Firm: ");
+ cputs(firm);
+ cputs(", Hong Kong");
+ show_damage();
+
+ gotoxy(21, 4);
+ in_use = hkw_[0] + hkw_[1] + hkw_[2] + hkw_[3];
+ cprintulong(in_use);
+
+ gotoxy(21, 6);
cprintulong(10000 - in_use);
gotoxy(12, 3);
- // printw("%d", hkw_[0]);
cprintulong(hkw_[0]);
gotoxy(12, 4);
- // printw("%d", hkw_[1]);
cprintulong(hkw_[1]);
gotoxy(12, 5);
- // printw("%d", hkw_[2]);
cprintulong(hkw_[2]);
gotoxy(12, 6);
- // printw("%d", hkw_[3]);
cprintulong(hkw_[3]);
- cputsxy(1, 8, "Hold ");
- if (hold >= 0)
- {
- // printw("%d", hold);
+ gotoxy(7, 8);
+ if (hold >= 0) {
cprintulong(hold);
} else {
revers(1);
@@ -1189,48 +1235,38 @@ void port_stats(void)
revers(0);
}
- cputsxy(16, 8, "Guns ");
- // printw("%d", guns);
+ gotoxy(22, 8);
cprintulong(guns);
- cputsxy(4, 9, "Opium ");
- // printw("%d", hold_[0]);
+ gotoxy(12, 9);
cprintulong(hold_[0]);
- cputsxy(4, 10, "Silk ");
- // printw("%d", hold_[1]);
+ gotoxy(12, 10);
cprintulong(hold_[1]);
- cputsxy(4, 11, "Arms ");
- // printw("%d", hold_[2]);
+ gotoxy(12, 11);
cprintulong(hold_[2]);
- cputsxy(4, 12, "General ");
- // printw("%d", hold_[3]);
+ gotoxy(12, 12);
cprintulong(hold_[3]);
- cputsxy(32, 2, "Date");
- cputsxy(29, 3, "15 ");
+ gotoxy(32, 3);
revers(1);
cputs(months[month - 1]);
revers(0);
cputc(' ');
- // printw(" %d", year);
cprintulong(year);
- cputsxy(30, 5, "Location");
revers(1);
cputsxy(30, 6, location[port]);
revers(0);
- cputsxy(32, 8, "Debt");
revers(1);
gotoxy(33, 9);
fancy_numbers(debt, fancy_num);
cputs(fancy_num);
revers(0);
- cputsxy(29, 11, "Ship Status");
gotoxy(29, 12);
i = status / 20;
if (i < 2) {
@@ -1241,10 +1277,10 @@ void port_stats(void)
cprintulong(status);
revers(0);
- cputsxy(0, 14, "Cash: ");
+ gotoxy(6, 14);
fancy_numbers(cash, fancy_num);
cputs(fancy_num);
- cputsxy(20, 14, "Bank: ");
+ gotoxy(26, 14);
fancy_numbers(bank, fancy_num);
cputs(fancy_num);
}
@@ -1263,6 +1299,19 @@ void splash_intro(void)
{
int i;
+ cursor(0);
+ gotoxy(0,23);
+#ifdef VERSION
+ cputs(VERSION);
+#else
+ cputs("(no version info)");
+#endif
+
+ /* if we print anything in this function, the character at (2,0)
+ gets inversed because the OS placed a cursor there. Fix it: */
+ gotoxy(2,0);
+ cputc(0xa0);
+
for(i=0; i<3; i++) draw_lorcha(i);
for(i=5; i<8; i++) draw_lorcha(i);
@@ -1274,12 +1323,13 @@ void splash_intro(void)
void mchenry(void)
{
- int choice = 0;
+ static int choice;
+ choice = 0;
compradores_report();
cputs("Taipan, Mc Henry from the Hong Kong\r\n");
- cputs("Shipyards has arrived!! He says, \"I see\r\n");
- cputs("ye've a wee bit of damage to yer ship.\r\n");
+ cputs("Shipyards has arrived!! He says, 'I see\r\n");
+ cputs("ye've a wee bit of damage to yer ship.'\r\n");
cputs("Will ye be wanting repairs? ");
while ((choice != 'Y') && (choice != 'y') &&
@@ -1292,8 +1342,10 @@ void mchenry(void)
{
// int percent = ((float) damage / capacity) * 100,
// this is likely wrong:
- int percent = ((damage * 100) / (capacity * 100)) * 100,
- time = ((year - 1860) * 12) + month;
+ static int percent, time;
+ static long br, repair_price, amount;
+ percent = ((damage * 100) / (capacity * 100)) * 100;
+ time = ((year - 1860) * 12) + month;
/*
long br = ((((60 * (time + 3) / 4) * (float) randi() / RAND_MAX) +
@@ -1302,7 +1354,6 @@ void mchenry(void)
amount;
*/
- long br, repair_price, amount;
br = ((randclamp(60 * (time + 3) / 4) + 25 * (time + 3) / 4) * capacity / 50);
repair_price = (br * damage) + 1;
@@ -1666,7 +1717,8 @@ void quit(void)
return;
} else {
- int num_ships = randi()%((capacity / 5) + guns) + 5;
+ static int num_ships;
+ num_ships = randi()%((capacity / 5) + guns) + 5;
cprintulong(num_ships);
cputs("ships of Li Yuen's pirate\r\n");