aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <yalhcru@gmail.com>2015-12-29 23:10:50 -0500
committerB. Watson <yalhcru@gmail.com>2015-12-29 23:10:50 -0500
commit2300d2813a524cbfeabac794335e7abe99263df6 (patch)
treed729ca4f99634788cbb3a2101a5b5854a4bc2d06
downloadtaipan-2300d2813a524cbfeabac794335e7abe99263df6.tar.gz
initial commit
-rw-r--r--LORCHA.DATbin0 -> 49 bytes
-rw-r--r--LORCHA.LST2
-rw-r--r--Makefile69
-rw-r--r--README.txt234
-rw-r--r--SOUND1.LST1
-rw-r--r--TITLE.DATbin0 -> 960 bytes
-rw-r--r--TITLE.LST5
-rw-r--r--apple_call_addresses11
-rw-r--r--applesounds.wavbin0 -> 14449964 bytes
-rw-r--r--bank.pl13
-rwxr-xr-xbitmapdump.pl34
-rw-r--r--characters55
-rw-r--r--convfont.c146
-rw-r--r--custom.cfg43
-rw-r--r--debt.pl17
-rw-r--r--dfoxtest.c210
-rw-r--r--draw_lorcha.s100
-rw-r--r--findfont.pl49
-rw-r--r--fontbin0 -> 768 bytes
-rw-r--r--fontrip.txt41
-rw-r--r--fonttmp109
-rw-r--r--jsleep.s11
-rw-r--r--lorcha.c9
-rw-r--r--lorcha.pl20
-rw-r--r--lorchatest.c37
-rw-r--r--oldcurses.c138
-rw-r--r--rand.s23
-rw-r--r--romfontbin0 -> 1024 bytes
-rw-r--r--taifontbin0 -> 1024 bytes
-rw-r--r--taipan-applesoft.txt961
-rw-r--r--taipan-orig.c2735
-rw-r--r--taipan.c2706
-rw-r--r--taipan.c_before_timed_getch2877
-rw-r--r--taipan.dskbin0 -> 143360 bytes
-rw-r--r--timed_getch.pl48
-rw-r--r--timed_getch.s26
-rw-r--r--title.pl7
37 files changed, 10737 insertions, 0 deletions
diff --git a/LORCHA.DAT b/LORCHA.DAT
new file mode 100644
index 0000000..e11c6fe
--- /dev/null
+++ b/LORCHA.DAT
Binary files differ
diff --git a/LORCHA.LST b/LORCHA.LST
new file mode 100644
index 0000000..b494971
--- /dev/null
+++ b/LORCHA.LST
@@ -0,0 +1,2 @@
+1 POKE 82,0›2 ? CHR$(125)›3 POSITION 0,0›5 OPEN #1,8,0,"H:LORCHA.DAT"›10 ? " = ="›20 ? "   ‹  "›30 ? "      "›40 ? "Š  ˆ   "›50 ? "
+ | |"›60 ? " ””””” "›70 ? "Š     ˆ"›100 FOR Y=0 TO 6›105 FOR X=0 TO 6›110 ? #1;CHR$(PEEK(40000+X+Y*40));›120 NEXT X›130 NEXT Y›140 CLOSE #1› \ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1d254e1
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,69 @@
+
+CC=cl65
+SYS=atari
+# COPT=-Oirs
+COPT=-O -l -T
+CFLAGS=-t $(SYS) -C custom.cfg -I. -L. $(COPT)
+AS=ca65
+ASFLAGS=-l
+AR=ar65
+
+# 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.
+
+# TITLE.DAT is generated by Atari BASIC code in TITLE.LST,
+# except last time I modified it, I exited the emulator without
+# saving the damn BASIC source, so TITLE.LST is outdated. TITLE.DAT
+# is a complete 960-byte dump of GR.0 screen memory, which gets
+# turned into title.xex and prepended to the main .xex. When
+# it loads, it goes straight to screen memory.
+
+# romfont is the 1K font extracted from the Atari 800 OS, with a
+# command like:
+# dd if=atariosb.rom of=1 bs=256 skip=8 count=4
+# ...where atariosb.rom comes from e.g. the PC-Xformer 2.5 zip file.
+
+XEX=taipan.xex
+
+all: $(XEX)
+
+$(XEX): taimain.xex taifont.xex title.xex
+ cat taifont.xex title.xex taimain.xex > $(XEX)
+
+title.xex: TITLE.DAT
+ perl title.pl TITLE.DAT > title.xex
+
+taimain.xex: taipan.c rand.s draw_lorcha.s
+ cl65 --mapfile taipan.map -t atari -O -l -T -o taimain.xex taipan.c rand.s draw_lorcha.s timed_getch.s jsleep.s
+
+taifont.xex: convfont romfont font
+ cat romfont font | ./convfont -x > taifont.xex
+ touch draw_lorcha.s
+
+taifont: convfont romfont font
+ cat romfont font | ./convfont > taifont
+
+convfont: convfont.c
+ gcc -Wall -o convfont convfont.c
+
+test: all
+ atari800 -nobasic $(XEX)
+
+.s.o:
+ $(AS) $(ASFLAGS) -o $@ $<
+
+.c.o:
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+clean:
+ rm -f *.o *.lst convfont
+
+distclean: clean
+ rm -f *~ core *.xex .*.swp 1.* 2.* 1 2 map map.* *.map
+
+%.xex: %.c
+ $(CC) --mapfile map $(CFLAGS) -o $@ $<
+
+lorchatest.xex: lorchatest.c draw_lorcha.s lorcha_data.inc
+ cl65 -t atari -O -l -T -o lorchatest.xex lorchatest.c draw_lorcha.s
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..b31622b
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,234 @@
+Taipan for Atari 800
+
+This is a work in progress. It's a port of the C version for Linux
+and curses, with the font and screen layout from the original Apple
+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.
+
+Linux/curses port can be found here:
+http://www.ibiblio.org/pub/linux/games/textrpg/
+
+Original Apple II BASIC source, plus a browser version of the game,
+can be found here: http://www.taipangame.com/
+
+What's missing:
+
+- Sound. The Linux/curses port doesn't have any, but I'm planning to
+ have the Atari mimic the sounds from the Apple II version, plus
+ maybe a few more (cannon shots and explosions during combat).
+
+- 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).
+
+- The title screen and ship graphics are pretty crude compared to
+ the Apple II original (though they're nicer than the curses ones).
+
+Building:
+
+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).
+
+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.
+
+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.
+
+License:
+
+The legal status of this is quite murky. The original game is still
+copyrighted, though quite a few clones of it have been made for various
+platforms over the years with no complaints from the copyright holder.
+
+This Atari build includes font data ripped straight from the original
+Apple game, plus more font data ripped from the Atari 800's OS ROM.
+
+The Linux port of taipan, according to its .lsm file, is GPL. My C code
+is definitely a derivative work, so it's GPL also. The assembly code and
+title/ship graphics are my own work, and I release them under the GPL
+(version 2).
+
+Notes:
+
+The Atari executable file format allows for concatenating executables.
+The result is still a valid executable. I use this to load the splash
+screen and custom font directly into memory before the main program loads.
+The Makefile documents how all this works, but it might seem pretty
+hairy if you're new to the Atari, Makefiles, and/or Perl.
+
+The Apple version of the game was expected to be run on a monochrome
+monitor. Like many other ports from the Apple to the Atari, there will
+be color artifacts when using a composite monitor. For best results,
+use a monochrome monitor. If you can't, at least try using a color
+monitor with S-Video (separate chroma/luma) inputs. If all else fails,
+try turning the color knob all the way down (and the contrast as high
+as you can stand it). In emulators, you can just disable artifacting.
+
+On PAL systems, the ship explosions and sinking animations will be a bit
+slower, and the prompt timeouts will be a bit longer. I don't think this
+is a real issue (it's not like Taipan is a fast-paced arcade game).
+
+Bugs! At least these:
+
+- Can't change orders in mid-battle. Whatever you pick for your first
+ turn, you're stuck with. Not sure why yet.
+
+- The damage calculation is messed up. You can get killed in your first
+ battle, one shot can occasionally destroy a 100% healthy ship.
+
+- When the lower-left ship get sunk, a little graphical "turd" gets
+ left behind.
+
+- This may or may not be fixed: Occasionally the font gets partly
+ corrupted in memory, by some rogue pointer or cc65 bug. The usual
+ symptom is that the vertical bars of the "box" in the port status
+ display get messed up. Still investigating this one. It ain't like
+ the Atari has valgrind :)
+
+- The "negative interest" bug is currently missing, due to using
+ unsigned values for debt. Plus, it's cheating. It'll get added back when
+ I either start using big numbers (floats or 64-bit ints or whatever),
+ or just decide to live with the limits of 32-bit ints.
+
+- The retirement display still uses ASCII | and - to draw a box. They
+ should be using ATASCII line-drawing characters instead (like the port
+ status does).
+
+- Retirement score calculations are a bit off, due to using integer math.
+
+- Not really a bug, but, the interest calculations for debt and the bank
+ are slightly different, due to using integer math. Very small bank or
+ debt amounts will grow much faster than they should, then stabilize
+ and converge towards the correct values over time. This only happens
+ when you have less than 10 in debt, or less than 200 in the bank,
+ which (at least for me) are pretty rare situations.
+
+- A few things in the screen layout are slightly off comapred to
+ the Apple version. Would really like to get it exact.
+
+- The cursor isn't getting disabled in a few places, and at some
+ prompts it's not visible until you actually type something.
+
+- Escape key should actually work, when typing at prompts.
+
+- fancy_numbers() maybe should round when it's showing a decimal point.
+ If you have e.g. 1,190,000, that should show as 1.2 million, not 1.1...
+ or maybe not (need to double-check against the Apple version).
+
+Differences between the Apple II original and Linux port:
+
+1. Linux has an 80-column screen layout, Apple is 40.
+2. Apple version uses a custom font (actually, two, but I'm ignoring that).
+3. Apple has sound, Linux does not.
+4. Apple has graphical title screen, Linux has ASCII art.
+5. Apple has graphical ships during battles, Linux has ASCII art.
+6. On Apple, price of General Cargo isn't always an integer (e.g. 6.5).
+ As a consequence, the cash and bank amounts aren't always ints either.
+7. On Apple, some Y/N prompts (like 'Do you have business with Elder Brother
+ Wu') you can press Enter for No. Linux port waits until you hit Y or N.
+8. On Apple, ships show damage (get holes in them) as they get shot up.
+9. On Linux, you can overpay McHenry (though you get no benefit from it).
+ On Apple, payment amount gets clamped to the repair price, so you can
+ e.g. be asked to pay 50,000 when you have 70,000 and safely enter A
+ (you'll end up 100% repaired and still have 20,000 cash).
+10. On Apple, dead enemy ships sink one scanline at a time, and there are
+ at least 2 sinking speeds. On Linux, it's one character at a time.
+
+The plan for the Atari port is to mimic the Apple version as closely as
+possible... except #6 above. It doesn't really add anything to the game,
+and it complicates the code more than I want to deal with. Also #10
+will probably not happen (to me, the slow ship-sinking of the Apple
+version is annoying anyway).
+
+Right now, items 1, 2, 5, 7, and 9 are implemented Apple-style; and 3,
+6, 8, 10 are Linux-style. 4 is kinda halfway between (the graphics are
+6 of the enemy ships rather than a hi-res single ship).
+
+Other things that need doing to the code:
+
+- Size optimization. Right now, the executable is almost 32K of code. I'd
+ like it to at least fit on a 16K cartridge. A lot of the C code is
+ redundant, and some things can be rewritten in asm if need be. I've
+ already eliminated all uses of printf() and its ilk, which removed 2K
+ of library code from the executable.
+
+- In aid of the above: split splash_intro(), cash_or_guns(), name_firm() into
+ separate .xex segments. Have to write a linker script to generate an
+ init header rather than a run header (or, write in raw asm and forget
+ the linker). Use cassette buffer and/or page 6 to pass variables to the main
+ program. name_firm() is 1/2K, cash_or_guns() is 1/4K, rewrite in asm and
+ they may both fit in page 6.
+
+- Another memory saver: keep some variables in page 6 and/or the tape
+ buffer. Also, find out how much page zero cc65 leaves us to
+ work with, maybe enough contiguous bytes for e.g. the fancy_num[]
+ buffer. draw_lorcha is using FR0 at $D4, but using it for fancy numbers
+ wouldn't conflict... it looks like cc65 uses 26 bytes of ZP from
+ $80-$99, so we have quite a bit free.
+
+- A thought: if memory gets too tight, switch to a boot disk rather than a
+ .xex file, and load code from disk at runtime (e.g. sea_battle() could be
+ loaded on top of some other routines, then the other routines reloaded
+ when the fight is over). That, or use a bankswitched cartridge.
+
+- Temporarily add a "god mode" to allow me to test situations that would take
+ a lot of regular gameplay to reach.
+
+- The title screen could be rearranged a bit and use a custom display list
+ to put all the text on top and bottom, with a GR.8 ship in the
+ middle. The Apple version's ship is a 176x145 bitmap, 22 bytes wide,
+ or 3190 bytes total on disk. Might use a narrow playfield to display
+ it? Or use GR.15 for a greyscale (greenscale) image?
+
+Future Ideas:
+
+I may do a "Taipan Plus" at some point. The regular Taipan game will be
+faithful to the original, and the Plus version could have some or all of:
+
+- More ports to dock at, some of which might have their own warehouses,
+ repair yards, etc.
+
+- More trade goods, not all of which are available at all ports.
+
+- Actual market trends, rather than a base price + random number. There
+ might be news events that cause prices to go up/down (e.g. Arms are
+ up at Saigon because there's a gang war in progress, Opium is up at
+ some port but the chances of getting busted are higher).
+
+- Ability to control a fleet of ships. Each one will either be a cargo
+ ship or a warship.
+
+- A "Turbo Combat" feature like one of the phone versions I've seen. You
+ set your orders and hit Turbo, and it finishes the fight instantly,
+ but you can't change your mind about your orders (fight until you win
+ or die, or run until you escape or die).
+
+- Special missions. Someone at some port needs you to transport documents
+ or whatever, to some other port... you will almost certainly be attacked
+ by whoever's trying to get the documents though.
+
+- Rival trading companies. Their activities can influence prices, and
+ you can fight them and possibly salvage actual cargo.
+
+- Variable passage of time. Distant ports take longer to get to. Also,
+ winds or ship damage can slow you down.
+
+I dunno how many of the above will fit in the Atari's RAM. Probably have
+to rewrite the whole game from scratch in assembly before adding features.
diff --git a/SOUND1.LST b/SOUND1.LST
new file mode 100644
index 0000000..fbfcdaa
--- /dev/null
+++ b/SOUND1.LST
@@ -0,0 +1 @@
+10 FOR I=1 TO 3›20 FOR J=20 TO 10 STEP -1›30 SOUND 0,J,10,10›40 NEXT J›50 NEXT I›1000 END › \ No newline at end of file
diff --git a/TITLE.DAT b/TITLE.DAT
new file mode 100644
index 0000000..83616aa
--- /dev/null
+++ b/TITLE.DAT
Binary files differ
diff --git a/TITLE.LST b/TITLE.LST
new file mode 100644
index 0000000..c17e1c5
--- /dev/null
+++ b/TITLE.LST
@@ -0,0 +1,5 @@
+1 REM POKE 764,60 for lowercase›5 POKE 752,1›10 POKE 82,0:? CHR$(125);›50 POSITION 0,0:? " Created by:"›60 POSITION 0,1:? " ม๒๔ รแ๎ๆ้์"›70 POSITION 0,3:? " "›72 POSITION 0,5:? " Atari 8-bit"›73 POSITION 0,6:? " Program by "›74 POSITION 0,7:? " ยฎ ืแ๔๓๏๎"›79 POSITION 0,9:? " "›80 POSITION 0,11:? " Copyright "›82 POSITION 0,12:? " (C) 1982 by"›84 POSITION 0,13:? " ม๖แ์แ๎ใ่ๅ"›85 POSITION 0,14:? " ะ๒๏ไ๕ใ๔้๏๎๓"›86 POSITION 0,15:? " ษ๎ใฎ "›88 POSITION 0,17:? " "›90 POSITION 0,19:? " Press มฮู "›92 POSITION 0,20:? " key to "›94 POSITION 0,21:? " start "›99 POSITION 0,0›100 ? "     
+       
+  
+ Œ 
+ Œ‹"›110 ? "                       "›120 ? "           ˆ         ‰"›130 ? "                    "›140 ? ""›150 ? " A GAME BASED ON THE CHINA"›160 ? " TRADE OF THE 1800'S"›900 OPEN #1,8,0,"H:TITLE.DAT"›910 FOR I=0 TO 959:? #1;CHR$(PEEK(40000+I));:NEXT I›920 CLOSE #1›1000 POSITION 0,18›1010 POKE 752,0› \ No newline at end of file
diff --git a/apple_call_addresses b/apple_call_addresses
new file mode 100644
index 0000000..8e536b7
--- /dev/null
+++ b/apple_call_addresses
@@ -0,0 +1,11 @@
+-958 fc42
+2200 898
+2224 8b0
+2368 940
+2512 9d0
+2518 9d6
+2521 9d9
+2524 9dc
+2560 a00
+2680 a78
+6147 1803
diff --git a/applesounds.wav b/applesounds.wav
new file mode 100644
index 0000000..d5642a6
--- /dev/null
+++ b/applesounds.wav
Binary files differ
diff --git a/bank.pl b/bank.pl
new file mode 100644
index 0000000..927012c
--- /dev/null
+++ b/bank.pl
@@ -0,0 +1,13 @@
+#!/usr/bin/perl -w
+
+my $debt = shift || 1000;
+my $idebt = $debt;
+
+my $months = shift || 100;
+for(1..$months) {
+ $debt += $debt * 0.005;
+ $idebt += ($idebt >> 8) + ($idebt >> 10);
+ # print "$debt\t$idebt\n";
+ $pct = $idebt * 100 / $debt;
+ printf("%.2d\t$idebt\t%.1d%%\n", $debt, $pct);
+}
diff --git a/bitmapdump.pl b/bitmapdump.pl
new file mode 100755
index 0000000..fb44a6f
--- /dev/null
+++ b/bitmapdump.pl
@@ -0,0 +1,34 @@
+#!/usr/bin/perl -w
+
+# browse through a binary file looking for bitmapped graphics,
+# especially fonts
+
+# user is expected to pipe through less
+
+$height = 8; # how many rows to display per block
+$width = 8; # how many blocks to display per line
+
+undef $/;
+$data = <>;
+
+for($offs=0; $offs<length($data); $offs += ($height * $width)) {
+ for my $char (0..$width-1) {
+ printf("%7x ", $offs + ($char * $height));
+ printf("%2x", $offs / $height + $char);
+ }
+
+ print "\n";
+
+ for my $line (0..$height-1) {
+ for my $char (0..$width-1) {
+ my $index = $offs + $line + ($char * $height);
+ if($index < length($data)) {
+ my $bitmap = sprintf(" %08b", ord(substr($data, $index, 1)));
+ $bitmap =~ s/0/./g;
+ $bitmap =~ s/1/X/g;
+ print $bitmap;
+ }
+ }
+ print "\n";
+ }
+}
diff --git a/characters b/characters
new file mode 100644
index 0000000..19f3ced
--- /dev/null
+++ b/characters
@@ -0,0 +1,55 @@
+
+Apple II lorcha is 49x40 pixels. The apple uses a 7x8 matrix for
+characters, so 7x5 characters. For the Atari with its 8x8 matrix, I cut
+off the leftmost column so it's now 48x40, or 6x5 = 30 characters. Of
+these, 6 are inverse spaces, 4 are regular spaces, and 3 are dups of
+other characters in the lorcha. Means we need 17 custom characters to
+draw an undamaged lorcha, leaving only 2 or 3 for showing damage.
+
+X = inverse space, . = space, A-Q are our custom chars.
+
+ 012345
+ ______
+0 |.ABC.D
+1 |.EXFGH
+2 |.EXFGI
+3 |JKLMNO
+4 |PXXXXQ
+
+name, screencode, 8 bytes of pixels, ascii
+A, 2, 00 00 00 00 00 00 ff 3f, "
+B, 3, 18 1f 1f 10 10 10 ff ff, #
+C, 4, 00 f0 fc 3e 00 00 fc f0, $
+D, 6, 00 00 40 70 7c 47 40 40, &
+E, 1b, 1f 3f ff 3f 1f 3f ff 7f, ;
+F, 1c, c0 f0 fc f0 c0 f0 fc f0, <
+G, 1d, 07 03 07 0f 07 03 07 f0, =
+H, 1e, fe fc fe ff fe f8 fe ff, >
+I, 20, fe f8 fe ff fe fe fd f9, @
+J, 3b, c0 fe ff ff ff ff 7f 1f, [
+K, 3c, 00 00 c0 ff 8f 8e 8e fe, \
+L, 3d, 38 38 38 38 ff 38 38 38, ]
+M, 3e, 00 00 00 01 ff e3 e3 e3, ^
+N, 3f, 00 00 00 ff 8d 8d 8d ff, _
+O, 40, c3 cf ff ff 3f 3e 3c f8, 0x00
+P, 46, 1f 0f 07 07 07 03 03 03, 0x06
+Q, 47, f0 e0 c0 c0 c0 c0 80 80, 0x07
+
+as screen data:
+
+80 02 03 04 00 06
+80 1b 80 1c 1d 1e
+80 1b 80 1c 1d 20
+3b 3c 3d 3e 3f 46
+40 80 80 80 80 47
+
+remaining unused characters, to be used for damage:
+50 5b 5d 5e 5f 60 7b 7d 7e 7f
+
+For damage, we can poke holes in the big sail with an inverse
+ball (^T). A couple of the portholes can be replaced with a
+custom 'crater' character. The right sail loses its flag (D)
+and its upper-right gets replaced with a custom char. The
+left sail can lose either of its F characters and have them
+replaced with a piece with a bite taken out of it.
+
diff --git a/convfont.c b/convfont.c
new file mode 100644
index 0000000..a2a2418
--- /dev/null
+++ b/convfont.c
@@ -0,0 +1,146 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <unistd.h>
+#include <stdio.h>
+
+/* usage:
+ # extract the 1K atari ROM font:
+ dd if=atariosb.rom of=romfont bs=256 skip=8 count=4
+
+ # extract the Apple II Taipan font:
+ dd if=taipan.dsk of=font bs=256 skip=54 count=3
+
+ # create the Atari 8-bit Taipan font:
+ cat romfont font | ./convfont > taifont.raw
+
+ # or, create the Atari 8-bit Taipan font as a binary load:
+ cat romfont font | ./convfont -x > taifont.xex
+ */
+
+/*
+ taipan font file order:
+ 0-31: `a-z{|}" block
+ 32-63: @A-Z[\]^_
+ 64-95: space !"#$%&'()*+,-./0-9:;>=<?
+
+ atari screen code order:
+ 0-31: space !"#$%&'()*+,-./0-9:;>=<?
+ 32-63: @A-Z[\]^_
+ 64-95 graphics chars
+ 96-127: `a-z and 4 graphics chars
+*/
+
+/* custom characters for ship graphics. 1st byte
+ is screencode, the other 8 are the pixel data. */
+char shipdata[][9] = {
+ {0x02 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x3f},
+ {0x03 , 0x18, 0x1f, 0x1f, 0x10, 0x10, 0x10, 0xff, 0xff},
+ {0x04 , 0x00, 0xf0, 0xfc, 0x3e, 0x00, 0x00, 0xfc, 0xf0},
+ {0x06 , 0x00, 0x00, 0x40, 0x70, 0x7c, 0x47, 0x40, 0x40},
+ {0x1b , 0x1f, 0x3f, 0xff, 0x3f, 0x1f, 0x3f, 0xff, 0x7f},
+ {0x1c , 0xc0, 0xf0, 0xfc, 0xf0, 0xc0, 0xf0, 0xfc, 0xf0},
+ {0x1d , 0x07, 0x03, 0x07, 0x0f, 0x07, 0x03, 0x07, 0x0f},
+ {0x1e , 0xfe, 0xfc, 0xfe, 0xff, 0xfe, 0xf8, 0xfe, 0xff},
+ {0x20 , 0xfe, 0xf8, 0xfe, 0xff, 0xfe, 0xfe, 0xfd, 0xf9},
+ {0x3b , 0xc0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f},
+ {0x3c , 0x00, 0x00, 0xc0, 0xff, 0x8f, 0x8e, 0x8e, 0xfe},
+ {0x3d , 0x38, 0x38, 0x38, 0x38, 0xff, 0x38, 0x38, 0x38},
+ {0x3e , 0x00, 0x00, 0x00, 0x01, 0xff, 0xe3, 0xe3, 0xe3},
+ {0x3f , 0x00, 0x00, 0x00, 0xff, 0x8e, 0x8e, 0x8e, 0xff},
+ {0x40 , 0xc3, 0xcf, 0xff, 0xff, 0x3f, 0x3e, 0x3c, 0xf8},
+ {0x46 , 0x1f, 0x0f, 0x07, 0x07, 0x07, 0x03, 0x03, 0x03},
+ {0x47 , 0xf0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80},
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+/* this ends up in LORCHA.DAT */
+char shipshape[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x03, 0x04, 0x00, 0x06,
+ 0x00, 0x00, 0x1b, 0x80, 0x1c, 0x1d, 0x1e,
+ 0x00, 0x00, 0x1b, 0x80, 0x1c, 0x1d, 0x20,
+ 0x00, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
+ 0x00, 0x46, 0x80, 0x80, 0x80, 0x80, 0x47,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+void bitswap(unsigned char *b, int lim) {
+ unsigned char j, k;
+ // fprintf(stderr, "bitswap(%x, %d)\n", b, lim);
+ do {
+ k = b[lim];
+ j = 0;
+ j |= (k & 0x01 ? 0x80 : 0);
+ j |= (k & 0x02 ? 0x40 : 0);
+ j |= (k & 0x04 ? 0x20 : 0);
+ j |= (k & 0x08 ? 0x10 : 0);
+ j |= (k & 0x10 ? 0x08 : 0);
+ j |= (k & 0x20 ? 0x04 : 0);
+ j |= (k & 0x40 ? 0x02 : 0);
+ j |= (k & 0x80 ? 0x01 : 0);
+ b[lim] = j;
+ } while(--lim > 0);
+}
+
+void clear0bits(unsigned char *b, int lim) {
+ do {
+ *b++ &= 0xfe;
+ } while(--lim > 0);
+}
+
+int main(int argc, char **argv) {
+ int i, j;
+ unsigned char font[1024], xex[6];
+
+ read(0, font, 1024);
+ read(0, font + (96 * 8), 32 * 8);
+ bitswap(font + (96 * 8), 32 * 8);
+ read(0, font + (32 * 8), 32 * 8);
+ bitswap(font + (32 * 8), 32 * 8);
+ read(0, font + (0 * 8), 32 * 8);
+ bitswap(font + (0 * 8), 32 * 8);
+
+ /* this stuff is from visual inspection via bitmapdump.pl */
+ clear0bits(font + 0x1f8, 7);
+ clear0bits(font + 0x301, 7);
+ clear0bits(font + 0x308, 8);
+ clear0bits(font + 0x330, 8);
+ clear0bits(font + 0x3a0, 8);
+ clear0bits(font + 0x3d8, 8);
+ clear0bits(font + 0x3e8, 8);
+ clear0bits(font + 0x040, 16);
+ clear0bits(font + 0x1e8, 8);
+
+ /* fix the vertical bar */
+ font[0x3e0] =
+ font[0x3e1] =
+ font[0x3e2] =
+ font[0x3e3] =
+ font[0x3e4] =
+ font[0x3e5] =
+ font[0x3e6] =
+ font[0x3e7] = 0x18;
+
+ /* stick ship data where it goes */
+ for(i=0; shipdata[i][0]; i++) {
+ for(j=0; j<8; j++) {
+ font[ shipdata[i][0] * 8 + j ] = shipdata[i][j+1];
+ }
+ }
+
+ if(argc > 1) {
+ xex[0] = xex[1] = 0xff;
+ xex[2] = 0x00; xex[3] = 0xb8; /* load address $B800 */
+ xex[4] = 0xff; xex[5] = 0xbb; /* end address $bbff */
+ write(1, xex, 6);
+ }
+ write(1, font, 1024);
+
+ i = open("LORCHA.DAT", O_WRONLY | O_CREAT);
+ write(i, shipshape, sizeof(shipshape));
+ close(i);
+
+ return 0;
+}
diff --git a/custom.cfg b/custom.cfg
new file mode 100644
index 0000000..7f0db8c
--- /dev/null
+++ b/custom.cfg
@@ -0,0 +1,43 @@
+FEATURES {
+STARTADDRESS: default = $2E00;
+}
+SYMBOLS {
+__STACKSIZE__ : value = $800, weak = yes;
+__RESERVED_MEMORY__: value = $0, weak = yes;
+}
+MEMORY {
+ZP: start = $0082, size = $007E, type = rw, define = yes;
+HEADER: start = $0000, size = $0006, file = %O;
+RAM: start = %S, size = $B7FF - __STACKSIZE__ - %S, file = %O;
+TRAILER: start = $0000, size = $0006, file = %O;
+}
+SEGMENTS {
+EXEHDR: load = HEADER, type = ro;
+STARTUP: load = RAM, type = ro, define = yes;
+LOWCODE: load = RAM, type = ro, define = yes, optional = yes;
+INIT: load = RAM, type = ro, optional = yes;
+CODE: load = RAM, type = ro, define = yes;
+RODATA: load = RAM, type = ro;
+DATA: load = RAM, type = rw;
+ZPSAVE: load = RAM, type = bss, define = yes;
+BSS: load = RAM, type = bss, define = yes;
+HEAP: load = RAM, type = bss, optional = yes;
+ZEROPAGE: load = ZP, type = zp;
+EXTZP: load = ZP, type = zp, optional = yes;
+AUTOSTRT: load = TRAILER, type = ro;
+}
+FEATURES {
+CONDES: segment = INIT,
+type = constructor,
+label = __CONSTRUCTOR_TABLE__,
+count = __CONSTRUCTOR_COUNT__;
+CONDES: segment = RODATA,
+type = destructor,
+label = __DESTRUCTOR_TABLE__,
+count = __DESTRUCTOR_COUNT__;
+CONDES: type = interruptor,
+segment = RODATA,
+label = __INTERRUPTOR_TABLE__,
+count = __INTERRUPTOR_COUNT__;
+}
+
diff --git a/debt.pl b/debt.pl
new file mode 100644
index 0000000..85a1841
--- /dev/null
+++ b/debt.pl
@@ -0,0 +1,17 @@
+#!/usr/bin/perl -w
+
+my $debt = shift || 1000;
+my $idebt = $debt;
+
+my $months = shift || 100;
+for(1..$months) {
+ $debt += $debt * 0.1;
+ if($idebt > 16) {
+ $idebt += (($idebt >> 4) + ($idebt >> 5) + ($idebt >> 7) - ($idebt >> 9));
+ } else {
+ $idebt++;
+ }
+ # print "$debt\t$idebt\n";
+ $pct = $idebt * 100 / $debt;
+ printf("%.2d\t$idebt\t%.1d%%\n", $debt, $pct);
+}
diff --git a/dfoxtest.c b/dfoxtest.c
new file mode 100644
index 0000000..aefdd5d
--- /dev/null
+++ b/dfoxtest.c
@@ -0,0 +1,210 @@
+/*#include <stdint.h>*/
+typedef char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef long int32_t;
+typedef unsigned long uint32_t;
+
+/*#include <stdbool.h>*/
+typedef uint8_t bool;
+#ifndef true
+ #define true 1
+#endif
+#ifndef false
+ #define false 0
+#endif
+
+/*Defines*/
+#define PREFIX_BITS_PER_BYTE 8
+ /*Neither can be greater than 128*/
+#define PREFIX_intsize 4
+#define PREFIX_INTSIZE 8
+
+/*Typedefs*/
+typedef uint8_t PREFIX_INT[PREFIX_INTSIZE];
+typedef int32_t PREFIX_int;
+
+/*Globals*/
+bool PREFIX_math_overflow;
+
+/*==============================================================CODE=============================================================*/
+
+void PREFIX_zero_int(PREFIX_INT *ptr)
+{
+ uint8_t i;
+
+ for (i = 0; i < PREFIX_INTSIZE; i++)
+ *ptr[i] = 0;
+}
+
+bool PREFIX_isneg(PREFIX_INT *in)
+{
+ return (*in[PREFIX_INTSIZE-1] & 0x80) >> 7;
+}
+
+void PREFIX_int_to_buf(PREFIX_INT *dest, PREFIX_int *src)
+{
+ PREFIX_int tmp;
+ uint8_t i;
+
+ tmp = *src;
+ for (i = 0; i < PREFIX_intsize; i++)
+ *dest[i] = (tmp >> (i*PREFIX_BITS_PER_BYTE)) & 0xFF;
+}
+
+void PREFIX_buf_to_int(PREFIX_int *dest, PREFIX_INT *src)
+{
+ PREFIX_int ret;
+ uint8_t i;
+
+ ret = 0;
+ for (i = 0; i < PREFIX_INTSIZE; i++) {
+ ret += dest[i];
+ ret <<= PREFIX_BITS_PER_BYTE;
+ }
+
+ *src[0] = ret;
+}
+
+void PREFIX_buf_to_buf(PREFIX_INT *dest, PREFIX_INT *src)
+{
+ uint8_t i;
+
+ for (i = 0; i < PREFIX_INTSIZE; i++)
+ *dest[i] = *src[i];
+}
+
+/*True to*/
+bool PREFIX_equal(PREFIX_INT *left, PREFIX_INT *right)
+{
+ uint8_t i;
+
+ for (i = 0; i < PREFIX_INTSIZE; i++)
+ if (*left[i] != *right[i])
+ return false;
+
+ return true;
+}
+
+/*greater than*/
+bool PREFIX_greater(PREFIX_INT *left, PREFIX_INT *right)
+{
+ uint8_t i;
+ bool left_neg, right_neg;
+
+ left_neg = PREFIX_isneg(left);
+ right_neg = PREFIX_isneg(right);
+
+ if (left_neg || right_neg) {
+ if (left_neg && !right_neg)
+ return false;
+ else if (!left_neg && right_neg)
+ return true;
+ }
+
+ for (i = 0; i < PREFIX_INTSIZE; i++) {
+ if (*left[i] > *right[i])
+ return true;
+ else if (*left[i] < *right[i])
+ return false;
+ }
+
+ return false;
+}
+
+/*less than*/
+bool PREFIX_less(PREFIX_INT *left, PREFIX_INT *right)
+{
+ return !PREFIX_greater(left, right);
+}
+
+/*greater than or equal to*/
+bool PREFIX_greater_or_equal(PREFIX_INT *left, PREFIX_INT *right)
+{
+ return PREFIX_greater(left, right) || PREFIX_equal(left, right);
+}
+
+/*less than or equal to*/
+bool PREFIX_less_or_equal(PREFIX_INT *left, PREFIX_INT *right)
+{
+ return PREFIX_less(left, right) || PREFIX_equal(left, right);
+}
+
+/*Negatives not currently supported*/
+void PREFIX_add(PREFIX_INT *dest, PREFIX_INT *src)
+{
+ /*operator*/
+ uint16_t op;
+ uint8_t i;
+ bool dest_neg, src_neg;
+
+ src_neg = PREFIX_isneg(src);
+ dest_neg = PREFIX_isneg(dest);
+
+ if (src_neg || dest_neg) {
+ PREFIX_math_overflow = true;
+ return;
+ }
+
+ for (i = 0; i < PREFIX_INTSIZE; i++) {
+ op = *src[i];
+ op += *dest[i];
+ *dest[i] = op & 0xFF;
+
+ op >>= PREFIX_BITS_PER_BYTE;
+ }
+
+ if (i == PREFIX_INTSIZE && op != 0)
+ PREFIX_math_overflow = true;
+
+ if (!(src_neg || dest_neg) && PREFIX_isneg(dest))
+ PREFIX_math_overflow = true;
+}
+
+/*Negatives not currently supported*/
+void PREFIX_sub(PREFIX_INT *dest, PREFIX_INT *src)
+{
+ uint16_t op;
+ uint8_t i, j;
+ bool dest_neg, src_neg;
+ uint16_t tmp_op = 0;
+ bool got_borrow = false;
+ PREFIX_INT tmp_dest, tmp_src;
+
+ src_neg = PREFIX_isneg(src);
+ dest_neg = PREFIX_isneg(dest);
+
+ if (src_neg || dest_neg)
+ PREFIX_math_overflow = true;
+
+ PREFIX_buf_to_buf(&tmp_src, src);
+ PREFIX_buf_to_buf(&tmp_dest, dest);
+ for (i = 0; i < PREFIX_INTSIZE; i++) {
+ op = tmp_dest[i];
+
+ if (tmp_src[i] > tmp_dest[i]) {
+ if (i == (PREFIX_INTSIZE-1))
+ PREFIX_math_overflow = true;
+
+ for (j = (i+1); j < PREFIX_INTSIZE; j++ )
+ if (tmp_dest[j]) {
+ tmp_dest[j] -= 1;
+ tmp_op = 0xFF;
+ got_borrow = true;
+ break;
+ }
+
+ if (!got_borrow)
+ PREFIX_math_overflow = true;
+
+ for (j--; j > i; j--)
+ tmp_src[j] = 0xFF;
+
+ op += tmp_op;
+ }
+
+ op -= tmp_src[i];
+ *dest[i] = op & 0xFF;
+ }
+}
diff --git a/draw_lorcha.s b/draw_lorcha.s
new file mode 100644
index 0000000..0f1a376
--- /dev/null
+++ b/draw_lorcha.s
@@ -0,0 +1,100 @@
+
+ .export _draw_lorcha
+ .import popax
+
+; TODO: maybe replace position tables with mul40? see
+; libsrc/atari/mul40.s, which is getting linked anyway
+; because conio uses it.
+
+; offset from start of screen for each ship position (0-9)
+lorcha_pos_lo:
+ .byte <320, <328, <336, <344, <352
+ .byte <640, <648, <656, <664, <672
+lorcha_pos_hi:
+ .byte >320, >328, >336, >344, >352
+ .byte >640, >648, >656, >664, >672
+
+; Atari OS's pointer to start of screen RAM
+ SAVMSC = $58
+
+; ZP working variables start at $d4, aka FR0 (floating point reg 0).
+ mask = $d4
+ displacement = $d5
+ destptr = $d6
+
+; Lorcha (boat), a type of sailing vessel having a Chinese
+; junk rig on a Portuguese or European style hull.
+; Our lorcha is a 7x7 block of ATASCII characters. We're storing
+; directly to screen RAM, so we use 'internal' codes.
+; To edit the graphics, load up LORCHA.LST in atari800, with the H:
+; device enabled, writable, set to current directory. Then edit the
+; quoted strings in lines 10-70, and RUN the program. It will
+; generate a new LORCHA.DAT, which must be 49 bytes long (so don't
+; change the lengths of the strings in the BASIC code!)
+lorcha_data:
+ .incbin "LORCHA.DAT"
+
+; void __fastcall__ draw_lorcha(int which, int displacement, int mask);
+_draw_lorcha:
+ sta mask ; stash mask (0 = normal, $80 = inverse)
+ jsr popax ; get displacement (0 = whole ship, 1..6 = sinking, 7 = blank)
+ sta displacement
+ jsr popax ; which ship position?
+ tax
+
+; setup pointer to screen offset of upper left of ship
+ lda lorcha_pos_lo,x
+ clc
+ adc SAVMSC
+ sta destptr
+ lda lorcha_pos_hi,x
+ clc
+ adc SAVMSC+1
+ sta destptr+1
+
+ ; first, draw any blank lines
+ ldx displacement ; are there any?
+ beq shiplineloop ; no, draw ship
+blanklineloop:
+ lda #0 ; screen code for space
+ ;ora mask ; apply mask ; don't need this here
+ ldy #6 ; ship is 7 columns wide (we count 6 to -1)
+blankcolloop:
+ sta (destptr),y
+ dey
+ bpl blankcolloop
+ jsr bump_pointer ; add 40 (1 line) to dest pointer.
+ dex
+ bne blanklineloop
+
+ ; X is now 0, however we got here.
+shiplineloop:
+ lda displacement
+ cmp #7
+ beq done
+ ldy #0
+shipcolloop:
+ lda lorcha_data,x
+ eor mask
+ sta (destptr),y
+ iny
+ inx
+ cpy #7
+ bne shipcolloop
+ jsr bump_pointer
+ inc displacement
+ clc
+ bcc shiplineloop
+
+done:
+ rts
+
+bump_pointer:
+ lda destptr
+ clc
+ adc #40
+ sta destptr
+ lda destptr+1
+ adc #0
+ sta 215
+ rts
diff --git a/findfont.pl b/findfont.pl
new file mode 100644
index 0000000..ead5392
--- /dev/null
+++ b/findfont.pl
@@ -0,0 +1,49 @@
+#!/usr/bin/perl -w
+
+# we're looking for this:
+
+# 00111000
+# 01000100
+# 10101000
+# 10100000
+# 10100000
+# 01000100
+# 00111000
+
+#@want = (
+#0b10101000,
+#0b10100000,
+#);
+
+@want = (
+0b00000101,
+0b00000101,
+);
+
+#@want = (
+#0b00111000,
+#0b01000100,
+#0b10101000,
+#0b10100000,
+#0b10100000,
+#0b01000100,
+#0b00111000,
+#);
+
+# or possibly a version of it shifted 1 or 2 bits to the right
+
+undef $/;
+$img = <>;
+@bytes = map { ord($_) } split //, $img;
+for($i = 0; $i < @bytes - 7; $i++) {
+ my $found = 1;
+ for($j = 0; $j < @want; $j++) {
+ if($bytes[$i+$j] != $want[$j]) {
+ $found = 0;
+ }
+ }
+ if($found) {
+ printf "offset: %x\n", $i;
+ }
+}
+
diff --git a/font b/font
new file mode 100644
index 0000000..0bf5eed
--- /dev/null
+++ b/font
Binary files differ
diff --git a/fontrip.txt b/fontrip.txt
new file mode 100644
index 0000000..0fa8fea
--- /dev/null
+++ b/fontrip.txt
@@ -0,0 +1,41 @@
+
+process of ripping the font was something like...
+
+look at a screenshot of the Apple 2 version, pick a byte that occurs on
+2 successive lines in a couple of the characters (I chose the 10100000
+that shows up in capital C and O).
+
+write perl script to find occurrences of 2 of that byte (findfont.pl)
+and print offsets of each one.
+
+use bitmapdump.pl to eyeball the file at those locations, until I found
+the letter C, then look up & down to find where the visible characters
+start and end. Use dd to grab just those bytes into another file.
+
+..except, the above was fruitless until I got the idea to search for the
+byte with its bits reversed (00000101). Turns out, the font is stored
+in the disk image with the bits reversed. Maybe if I knew the Apple
+architecture, I'd have already known that?
+
+Anyway. To create an atari font, I mapped out the order the characters
+appear in the dump, and wrote convfont.c to overlay them onto the Atari
+ROM font (created from atariosb.rom with dd)... and for some reason,
+a few of the characters have vertical bars in the rightmost position,
+caused by bit 7 (in the original reversed format) being set. convfont.c
+just zeroes those out as needed.
+
+The end result is taifont.xex, containing 1024 bytes of data to be
+loaded at $BB00.
+
+To get it to work with a cc65 program, I had to create a linker script
+(custom.cfg). Ran this:
+
+ld65 --dump-config atari > custom.cfg
+
+Then edited it... all I changed was the ending address, which is
+now $B7FF (one byte below the font's load address). After compiling a
+taipan.xex with this config, I append taifont.xex and taipan.xex to make
+taipantext.xex (the finished game).
+
+The only thing the C code needs to do is POKE(756, 0xbb) in main()
+before printing any text.
diff --git a/fonttmp b/fonttmp
new file mode 100644
index 0000000..9285c9c
--- /dev/null
+++ b/fonttmp
@@ -0,0 +1,109 @@
+
+ X....X.. X....... ......X. ........ ..X..... ........ X..XX... ........
+ X...X... X....... ......X. ........ ..X..... ........ X.X..X.. ........
+ X..X.... X...XXX. ...XX.X. ...XXX.. ..X.XX.. ...XXX.. X....X.. ..X.XX..
+ X....... X..X.... ..X..XX. ..X...X. ..XX..X. ..X...X. X..XXXXX ..XX..X.
+ X....... X..XXXX. ..X...X. ......X. ..X...X. ..XXXXX. X....X.. ..XX..X.
+ X....... X..X...X ..X..XX. ..X...X. ..XX..X. ......X. X....X.. ..X.XX..
+ X....... X.X.XXX. ...XX.X. ...XXX.. ..X.XX.. ...XXX.. X....X.. ..X.....
+ X....... X....... ........ ........ ........ ........ X....... ...XXX..
+
+ ......X. ....X... ..X..... ......X. ....XX.. ........ ........ ........
+ ......X. ........ ........ ......X. ....X... ........ ........ ........
+ ...XX.X. ....XX.. ..XX.... ..X...X. ....X... ...XXXXX ...XX.X. ...XXX..
+ ..X..XX. ....X... ..X..... ...X..X. ....X... ..X.X.X. ..X..XX. ..X...X.
+ ..X...X. ....X... ..X..... ....X.X. ....X... ..X.X.X. ..X...X. ..X...X.
+ ..X...X. ....X... ..X..... ...X.XX. ....X... ..X.X.X. ..X...X. ..X...X.
+ ..X...X. ...XXX.. ..X...X. ..X...X. ...XXX.. ..X.X.X. ..X...X. ...XXX..
+ ........ ........ ...XXX.. ........ ........ ........ ........ ........
+
+ ........ ........ ........ ........ X....X.. ........ ........ ........
+ ........ ........ ........ ........ X....X.. ........ ........ ........
+ ...XX.X. ..X.XX.. ...XX.X. ..XXXX.. X..XXXXX ..X...X. ..X...X. ..X...X.
+ ..X..XX. ..XX..X. ..X..XX. ......X. X....X.. ..X...X. ..X...X. ..X.X.X.
+ ..X..XX. ..XX..X. ......X. ...XXX.. X....X.. ..X...X. ..X...X. ..X.X.X.
+ ...XX.X. ..X.XX.. ......X. ..X..... X.X..X.. ..XX..X. ...X.X.. ..X.X.X.
+ ......X. ..X..... ......X. ...XXXX. X..XX... ..X.XX.. ....X... ..XX.XX.
+ ......X. ..X..... ........ ........ X....... ........ ........ ........
+
+ ........ ........ ........ X.XXX... ....X... X...XXX. ...X.X.. XXXXXXXX
+ ........ ........ ........ X....X.. ....X... X..X.... ....X.X. XXXXXXXX
+ ..X...X. ..X...X. ..XXXXX. X....X.. ....X... X..X.... ........ XXXXXXXX
+ ...X.X.. ..X...X. ...X.... X.....X. ....X... X.X..... ........ XXXXXXXX
+ ....X... ..X...X. ....X... X....X.. ....X... X..X.... ........ XXXXXXXX
+ ...X.X.. ..XXXX.. .....X.. X....X.. ....X... X..X.... ........ XXXXXXXX
+ ..X...X. ..X..... ..XXXXX. X.XXX... ....X... X...XXX. ........ XXXXXXXX
+ ........ ...XXX.. ........ X....... ....X... X....... ........ XXXXXXXX
+
+ ...XXX.. .....XX. ...XXX.X ...XXX.. ....XX.X ...XXX.X ...XXX.X ...XXX..
+ ..X...X. ....X..X ..X...X. ..X...X. ...X..XX ..X...X. ..X...X. ..X...X.
+ ..X.X.X. ...X.X.. ..X....X ...X.X.X ..X....X .......X ......X. .......X
+ ..XX.XX. ..X...X. ...XXXXX .....X.X ..X....X ....XXXX ....XXXX ..XXXX.X
+ ...XX.X. ..XXXXX. ..X....X .....X.X ..X....X .......X ......X. ..X...XX
+ ......X. ..X...X. ..X...X. ..X...X. ...X..XX ..X...X. ......X. ..XXXXX.
+ ..XXXX.. .X.....X ...XXX.X ...XXX.. ....XX.X ...XXX.X .......X ..X.....
+ ........ ........ ........ ........ ........ ........ ........ ..XX....
+
+ .X.....X .X...... .X...... ..X....X ....XX.. ...X.X.X .X.....X ...XXX..
+ ..X...X. ..XXXXX. ..X..... ...X..X. ...X..X. ..X.X.X. ..X..XX. ..X...X.
+ ..X...X. ....X..X ..X..... ....X.X. ......X. ..X.X.X. ..X.X.X. .X...X.X
+ ..XXXXX. ....X... ..X..... .....XXX ......X. ..X.X.XX ..X.X.XX .X...X.X
+ ..X...X. .X..X... ..X...X. ....X.X. ......X. ..X.X.X. ..X.X.X. .X...X.X
+ ..X...X. ..XXXXX. ...X...X ...X..X. .X....X. ..X.X.X. ..X.X.X. ..X...X.
+ .X.....X .......X ....XXX. ..X....X ..XXXX.X .......X ...X...X ...XXX..
+ ........ ........ ........ ........ ........ ........ ........ ........
+
+ ...XXX.X ...XXX.. ...XXX.X .X...... .X...... .X....X. ..XX..X. .......X
+ ..X...X. ..X...X. ..X...X. ..XXXXX. ..XXXXXX ..X..X.X .X..XX.X ..XXX.X.
+ ..X...X. .X...X.X ..X...X. .......X .....XX. ..X..X.. .X...X.. .X..X.X.
+ ...XXXXX .X...X.X ...XXXXX ..XXXXX. .....X.X ..X..X.. .X...X.. .X..X.X.
+ ......X. .X.X.X.X ...X..X. .X...... .....X.X ..X..X.. .X...X.. .X..X.X.
+ ......X. ..X...X. ..X...X. ..XXXXX. .X....X. ..X..X.. ..X.X... ..X.X.X.
+ .......X .X.XXX.. ..X....X .......X ..XXXX.. ...XX... ...X.... ...X.X..
+ ........ .X...... ........ ........ ........ ........ ........ ........
+
+ .X....X. .X....X. ..XXXXX. ...XXXX. ........ X..XXXX. ....X... X.......
+ ..X..X.X ..X..X.X ..X..... ......X. .......X X..X.... ...XXX.. X.......
+ ...XX... ..X..X.. ...X.... ......X. ......X. X..X.... ..X.X.X. X.......
+ ....X... ..X..X.. ....X... ......X. .....X.. X..X.... ....X... X.......
+ ....XX.. .X.XX... .....X.. ......X. ....X... X..X.... ....X... X.......
+ .X.X..X. .X.....X ......X. ......X. ...X.... X..X.... ....X... X.......
+ ..X....X ..XXXXX. ..XXXXX. ...XXXX. ..X..... X..XXXX. ....X... X.......
+ ........ ........ ........ ........ ........ X....... ........ XXXXXXXX
+
+ ........ ....X... ..XX.XX. X..X.X.. ....X... ........ X...X... ....XX..
+ ........ ....X... ..XX.XX. X..X.X.. ..XXXX.. ..X...XX X..X.X.. ....XX..
+ ........ ....X... ..XX.XX. X.XXXXX. ....X.X. ...X..XX X..X.X.. ....XX..
+ ........ ....X... ........ X..X.X.. ...XXX.. ....X... X....X.. ........
+ ........ ........ ........ X.XXXXX. ..X.X... .....X.. X...X.X. ........
+ ........ ........ ........ X..X.X.. ...XXXX. ..XX..X. X..X..X. ........
+ ........ ....X... ........ X..X.X.. ....X... ..XX...X X.X.XX.. ........
+ ........ ........ ........ X....... ........ ........ X....... ........
+
+ X..X.... X....X.. ....X... ........ ........ ........ ........ ........
+ X...X... X...X... ..X.X.X. ....X... ........ ........ ........ ..X.....
+ X....X.. X..X.... ...XXX.. ....X... ........ ........ ........ ...X....
+ X....X.. X..X.... ..XXXXX. ..XXXXX. ........ ..XXXXX. ........ ....X...
+ X....X.. X..X.... ...XXX.. ....X... ........ ........ ........ .....X..
+ X...X... X...X... ..X.X.X. ....X... ....X... ........ ....XX.. ......X.
+ X..X.... X....X.. ....X... ........ ....X... ........ ....XX.. .......X
+ X....... X....... ........ ........ .....X.. ........ ........ ........
+
+ ........ ........ ........ ........ ........ ........ ........ ........
+ ...XXX.. ....X... ...XXX.. ...XXX.. ...X..X. ..XXXXX. ...XXX.. ..XXXXX.
+ ..X...X. ....XX.. ..X...X. ..X...X. ...X..X. ......X. ......X. ..X...X.
+ ..X...X. ....X... ..XX.... ...XX... ...X..X. ...XXXX. ...XXXX. ...X....
+ ..X...X. ....X... ....XX.. ..X..... ..XXXXX. ..X..... ..X...X. ....X...
+ ..X...X. ....X... ......X. ..X...X. ...X.... ..X...X. ..X...X. ....X...
+ ...XXX.. ..XXXXX. ..XXXXX. ...XXX.. ...X.... ...XXX.. ...XXX.. ....X...
+ ........ ........ ........ ........ ........ ........ ........ ........
+
+ ........ ........ ........ ........ ..XX.... ........ .....XX. ...XXX..
+ ...XXX.. ...XXX.. ........ ........ ....X... ........ ....X... ..X...X.
+ ..X...X. ..X...X. ....X... ....X... .....X.. ..XXXXX. ...X.... ..X.....
+ ...XXX.. ..XXXX.. ........ ........ ......X. ........ ..X..... ...X....
+ ..X...X. ..X..... ........ ........ .....X.. ..XXXXX. ...X.... ....X...
+ ..X...X. ...X.... ....X... ....X... ....X... ........ ....X... ........
+ ...XXX.. ....XX.. ........ ....X... ..XX.... ........ .....XX. ....X...
+ ........ ........ ........ .....X.. ........ ........ ........ ........
+
diff --git a/jsleep.s b/jsleep.s
new file mode 100644
index 0000000..e052ddd
--- /dev/null
+++ b/jsleep.s
@@ -0,0 +1,11 @@
+
+ .export _jsleep
+ .import _set_jiffy_timer
+
+_jsleep:
+ jsr _set_jiffy_timer
+wait:
+ lda 540
+ ora 541
+ bne wait
+ rts
diff --git a/lorcha.c b/lorcha.c
new file mode 100644
index 0000000..156c735
--- /dev/null
+++ b/lorcha.c
@@ -0,0 +1,9 @@
+char lorcha[] = {
+ 0x20, 0x20, 0x01, 0x3d, 0x20, 0x01, 0x3d,
+ 0x0b, 0xa0, 0xa0, 0x8b, 0x0b, 0xa0, 0x0f,
+ 0x0b, 0xa0, 0xa0, 0xa0, 0x0b, 0xa0, 0x0f,
+ 0x8a, 0xa0, 0xa0, 0x88, 0x0b, 0xa0, 0x20,
+ 0x0a, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x08,
+ 0xa0, 0x94, 0x94, 0x94, 0x94, 0x94, 0xa0,
+ 0x8a, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x88,
+}
diff --git a/lorcha.pl b/lorcha.pl
new file mode 100644
index 0000000..8d09a71
--- /dev/null
+++ b/lorcha.pl
@@ -0,0 +1,20 @@
+#!/usr/bin/perl -w
+
+# LORCHA.LST is a LISTed BASIC program that draws a lorcha
+# and spits out the screen data to H:LORCHA.DAT (for which
+# you will need atari800's H: device pointed at the current
+# directory).
+
+# Usage:
+# atari800 -basic LORCHA.LST
+# perl lorcha.pl LORCHA.DAT > lorcha_data.inc
+
+use bytes;
+undef $/;
+$data = <>;
+print "lorcha_data:\n";
+for(0..6) {
+ print " .byte ";
+ print join ", ", map { sprintf '$%02x', ord $_ } split "", substr($data, $_ * 6, 7);
+ print "\n";
+}
diff --git a/lorchatest.c b/lorchatest.c
new file mode 100644
index 0000000..bc53d07
--- /dev/null
+++ b/lorchatest.c
@@ -0,0 +1,37 @@
+#include <peekpoke.h>
+
+extern void __fastcall__ draw_lorcha(int which, int displacement, int mask);
+
+void jsleep(int jiffies) {
+ POKE(20,0);
+ while(PEEK(20) < jiffies)
+ ;
+}
+
+int main(void) {
+ int i, j;
+
+ /* draw all 10 ships in normal state */
+ for(i=0; i<10; i++) {
+ draw_lorcha(i, 0, 0);
+ }
+
+ /* explode and sink all 10 ships */
+ for(i=0; i<10; i++) {
+ /* blast effect */
+ for(j=0; j<8; j++) {
+ draw_lorcha(i, 0, 0x80);
+ jsleep(2);
+ draw_lorcha(i, 0, 0);
+ jsleep(2);
+ }
+
+ /* sinking */
+ for(j=0; j<8; j++) {
+ draw_lorcha(i, j, 0);
+ jsleep(4);
+ }
+ }
+
+hang: goto hang;
+}
diff --git a/oldcurses.c b/oldcurses.c
new file mode 100644
index 0000000..44ff6b3
--- /dev/null
+++ b/oldcurses.c
@@ -0,0 +1,138 @@
+/* curses wrappers.
+ The original code uses curses, cc65 uses conio, so I wrote this stuff
+ to map the curses calls to conio ones.
+ Later on, just replaced all the curses stuff (except clrtobot() and
+ clrtoeol()) with direct calls to conio.
+ Keeping this around in case it's useful for porting some other
+ curses app to cc65. */
+
+/* original plan was to use time() or _systime(). It turns out that
+ these are not implemented on the Atari, and always return -1.
+ So, use the OS's countdown timer instead.
+ Anyone porting to another cc65 platform needs to rewrite this.
+
+ TODO: rewrite in terms of clock() and CLOCKS_PER_SEC. Will make it
+ less atari-specific, plus auto-adjust for pal/ntsc.
+
+ TODO: there is atari-specific stuff elsewhere in the code :(
+ */
+
+static unsigned int tmout_jiffies = 0;
+
+/*
+void timeout(unsigned int msec) {
+ if(msec > 0)
+ tmout_jiffies = (msec / 100) * 6; // TODO: should be 5 for PAL
+ else
+ tmout_jiffies = 0;
+}
+*/
+
+/* set timer with interrupts disabled, to avoid race condition
+ where an interrupt happens between setting the high & low bytes. */
+void start_timer() {
+ __asm__("SEI");
+ POKE(541, tmout_jiffies / 256);
+ POKE(540, tmout_jiffies % 256);
+ __asm__("CLI");
+}
+
+/* this getch() works like curses, except it always acts
+ like it's in cbreak mode. */
+int getch() {
+ int ret = -1;
+
+ if(tmout_jiffies == 0) return cgetc();
+
+ start_timer();
+
+ do {
+ if(kbhit()) {
+ ret = cgetc();
+ break;
+ }
+ } while (timer_running());
+
+ return ret;
+}
+
+#define timer_running() (PEEK(541) || PEEK(540))
+#define timer_expired() (!timer_running())
+
+int flushinp() {
+ POKE(764, 255);
+ return 0;
+}
+
+void clrtobot() {
+ unsigned char rows, cols, y, oldx, oldy;
+ oldx = wherex();
+ oldy = wherey();
+ screensize(&cols, &rows);
+ cclear(cols - wherex()); /* leaves cursor at start of next line */
+ for(y = wherey(); y < rows; y++)
+ cclearxy(0, y, cols);
+ gotoxy(oldx, oldy);
+}
+
+/* one-to-one mapping between some of the conio API and the curses one */
+#define clear() clrscr()
+#define printw cprintf
+#define curs_set(x) cursor(x)
+
+/* conio doesn't do deferred printing, refresh() is a no-op */
+#define refresh()
+
+/* we don't support cooked or raw mode, cbreak() is a no-op */
+#define cbreak()
+
+/* we don't support echo mode */
+#define noecho()
+
+/* curses move() takes args in the opposite order to gotoxy() */
+#define move(a, b) gotoxy(b, a)
+
+/* our attrset() only supports A_NORMAL and A_REVERSE, since
+ the Atari can only print normal and reverse video. */
+#define A_NORMAL 0
+#define A_REVERSE 1
+#define attrset(x) revers(x)
+
+/**** atari-specific stuff */
+
+/* original plan was to use time() or _systime(). It turns out that
+ these are not implemented on the Atari, and always return -1.
+ So, use the OS's countdown timer instead.
+ Anyone porting to another cc65 platform needs to rewrite this.
+
+ TODO: rewrite in terms of clock() and CLOCKS_PER_SEC. Will make it
+ less atari-specific, plus auto-adjust for pal/ntsc.
+
+ TODO: there is atari-specific stuff elsewhere in the code :(
+ */
+
+static unsigned int tmout_jiffies = 0;
+
+void timeout(unsigned int msec) {
+ if(msec > 0)
+ tmout_jiffies = (msec / 100) * 6; // TODO: should be 5 for PAL
+ else
+ tmout_jiffies = 0;
+}
+
+/* set timer with interrupts disabled, to avoid race condition
+ where an interrupt happens between setting the high & low bytes. */
+void start_timer() {
+ __asm__("SEI");
+ POKE(541, tmout_jiffies / 256);
+ POKE(540, tmout_jiffies % 256);
+ __asm__("CLI");
+}
+
+#define timer_running() (PEEK(541) || PEEK(540))
+#define timer_expired() (!timer_running())
+
+int flushinp() {
+ POKE(764, 255);
+ return 0;
+}
diff --git a/rand.s b/rand.s
new file mode 100644
index 0000000..c48478e
--- /dev/null
+++ b/rand.s
@@ -0,0 +1,23 @@
+
+ .export _randi, _randl
+ .importzp sreg
+
+RANDOM = 53770 ; POKEY LFSR read address, defined in the Atari OS
+
+; void __fastcall__ randi(void);
+_randi:
+ lda #0
+ sta sreg
+ beq randl1
+
+; void __fastcall__ randl(void);
+_randl:
+ lda RANDOM
+randl1:
+ sta sreg
+ lda RANDOM
+ sta sreg+1
+ lda RANDOM
+ ldx RANDOM
+ rts
+
diff --git a/romfont b/romfont
new file mode 100644
index 0000000..2e680b2
--- /dev/null
+++ b/romfont
Binary files differ
diff --git a/taifont b/taifont
new file mode 100644
index 0000000..2da7e59
--- /dev/null
+++ b/taifont
Binary files differ
diff --git a/taipan-applesoft.txt b/taipan-applesoft.txt
new file mode 100644
index 0000000..5cf95aa
--- /dev/null
+++ b/taipan-applesoft.txt
@@ -0,0 +1,961 @@
+
+]LIST
+
+ 10 CLEAR :WK$ = "*":CH$ = "*":C
+ H% = 0:WU% = 0:R1% = 0:I = 0
+ :J = 0:K = 0:II = 0:IJ = 0:I
+ K = 0:T = 300:LT = LOG (10)
+ :T$ = "Taipan": GOTO 10000
+ 90 REM
+ 92 FOR II = 1 TO T:II = II + ( PEEK
+ ( - 16384) > 127) * 9999: NEXT
+ II
+ 94 FOR II = 1 TO T / 2:II = II +
+ ( PEEK ( - 16384) > 127) * 9
+ 999: NEXT II
+ 96 FOR II = 1 TO T / 2:II = II +
+ ( PEEK ( - 16384) > 127) * 9
+ 999: NEXT II
+ 98 POKE - 16368,0: RETURN
+ 100 CALL 2560: RETURN
+ 150 WK$ = "" + " ": CALL
+ 2680:W = VAL (WK$):R1% = LEFT$
+ (WK$,1) = "A": RETURN
+ 200 REM
+ 210 PRINT FS$;HM$;CS$; SPC( 12 -
+ LEN (H$) / 2): PRINT "Firm:
+ ";CA$;H$;CS$;", ";:X = USR
+ (1): PRINT
+ 220 VTAB 2: PRINT CG$;"[";: & 4
+ 5,26: PRINT "]": FOR II = 1 TO
+ 5: PRINT "!"; TAB( 28);"!": NEXT
+ II: PRINT "(";: & 61,26: PRINT
+ ")": FOR II = 1 TO 5: PRINT
+ "!"; TAB( 28);"!": NEXT II: PRINT
+ "<";: & 58,26: PRINT ">";CS$
+
+ 230 VTAB 3: HTAB 2:X = USR (1)
+ + USR (2): VTAB 4: HTAB 21
+ : PRINT "In use:": VTAB 6: HTAB
+ 21: PRINT "Vacant:": VTAB 9:
+ HTAB 2: PRINT "Hold
+ Guns";
+ 240 FOR II = 3 TO 9 STEP 6: FOR
+ IJ = 1 TO 4: VTAB II + IJ: HTAB
+ 5: PRINT LEFT$ (CO$(IJ),7);
+ : NEXT IJ,II
+ 250 VTAB 3: HTAB 33: PRINT "Dat
+ e": VTAB 6: HTAB 31:X = USR
+ (3): VTAB 9: HTAB 33: PRINT
+ "Debt": VTAB 12: HTAB 29: PRINT
+ " Ship status":
+ 260 VTAB 16: HTAB 1: PRINT CG$;
+ : & 45,40: PRINT CS$
+ 270 RETURN
+ 300 REM
+ 310 VTAB 4: HTAB 30: PRINT "15
+ ";YE: VTAB 4: HTAB 33: PRINT
+ IV$; MID$ ("JanFebMarAprMayJ
+ unJulAugSepOctNovDec",(MO -
+ 1) * 3 + 1,3);NV$
+ 311 VTAB 7: HTAB 31: PRINT "
+ ": VTAB 7: HTAB 35 - LEN
+ (LO$(LO)) / 2 + .5: PRINT IV
+ $;LO$(LO);NV$
+ 312 VTAB 10: HTAB 29: PRINT "
+ ": VTAB 10:WW = DW
+ : GOSUB 600: HTAB 35 - LEN
+ (WW$) / 2: PRINT IV$;WW$;NV$
+
+ 313 WW = 100 - INT (DM / SC * 1
+ 00 + .5):WW = WW * (WW > 0):
+ W = INT (WW / 20): VTAB 13:
+ HTAB 30: IF W < 2 THEN PRINT
+ IV$;
+ 314 PRINT ST$(W);":";WW;: IF PEEK
+ (36) > 30 THEN PRINT TAB(
+ 40);" ";
+ 315 PRINT NV$;
+ 316 VTAB 5: HTAB 22: PRINT "
+ ";: HTAB 22: PRINT WS: VTAB
+ 7: HTAB 22: PRINT " ";: HTAB
+ 22: PRINT WC - WS
+ 320 POKE 32,12: FOR II = 1 TO 2
+ : POKE 33,(II - 1) * 9 + 6:I
+ K = II * 6 - 3: POKE 34,IK: POKE
+ 35,IK + 4: PRINT HM$: FOR IJ
+ = 1 TO 4: VTAB IK + IJ: HTAB
+ 1: PRINT ST(II,IJ);: NEXT IJ
+ ,II
+ 330 PRINT FS$: VTAB 15: HTAB 1:
+ WW = CA: GOSUB 600: PRINT "C
+ ash:";WW$; TAB( 21);:WW = BA
+ : GOSUB 600: PRINT "Bank:";W
+ W$; TAB( 40);" ": VTAB 9: HTAB
+ 22: PRINT GN;: HTAB 7: PRINT
+ " ";: HTAB 7
+ 340 IF MW < 0 THEN PRINT IV$;"
+ Overload";NV$
+ 350 IF MW > = 0 THEN PRINT MW
+ ;
+ 360 RETURN
+ 400 REM
+ 410 POKE 32,0: POKE 33,40: POKE
+ 34,18: POKE 35,24: PRINT HM$
+ ;: RETURN
+ 480 VTAB 17: HTAB 1:X = USR (4
+ ): RETURN
+ 490 VTAB 17: HTAB 1:X = USR (5
+ ): RETURN
+ 500 REM
+ 510 GOSUB 400:X = USR (6): GOSUB
+ 150: IF R1% THEN W = CA
+ 530 IF CA > = W THEN CA = CA -
+ W:BA = BA + W: GOSUB 300: GOTO
+ 550
+ 540 PRINT : PRINT : PRINT T$;:X
+ = USR (8): PRINT CA: PRINT
+ "in cash.": CALL 2518: GOSUB
+ 94: GOTO 510
+ 550 GOSUB 400:X = USR (7): GOSUB
+ 150: IF R1% THEN W = BA
+ 570 IF BA > = W THEN BA = BA -
+ W:CA = CA + W: GOSUB 300: GOTO
+ 590
+ 580 PRINT : PRINT : PRINT T$;:X
+ = USR (8): PRINT BA: PRINT
+ "in the bank.": CALL 2518: GOSUB
+ 94: GOTO 550
+ 590 RETURN
+ 600 IF WW < 1E6 THEN WW$ = STR$
+ ( INT (WW)): RETURN
+ 610 II = INT ( LOG (WW) / LT):I
+ J = INT (II / 3) * 3:IK = 1
+ 0 ^ (II - 2):WW$ = LEFT$ ( STR$
+ ( INT (WW / IK + .5) * IK /
+ 10 ^ IJ),4) + " "
+ 620 IF IJ = 3 THEN W$ = "Thousa
+ nd"
+ 630 IF IJ = 6 THEN W$ = "Millio
+ n"
+ 640 IF IJ = 9 THEN W$ = "Billio
+ n"
+ 650 IF IJ = 12 THEN W$ = "Trill
+ ion"
+ 680 WW$ = WW$ + W$
+ 690 RETURN
+ 1000 REM
+ 1010 IF D < > 0 THEN GOSUB 49
+ 0: GOSUB 400:X = USR (9): PRINT
+ LO$(D): GOSUB 96:BA = INT (
+ BA + BA * .005):DW = INT (D
+ W + DW * .1):TI = TI + 1:MO =
+ MO + 1:LO = D
+ 1020 IF MO > 12 THEN YE = YE +
+ 1:MO = 1:EC = EC + 10:ED = E
+ D + .5: FOR I = 1 TO 7: FOR
+ J = 1 TO 4:BP%(I,J) = BP%(I,
+ J) + FN R(2): NEXT J,I
+ 1030 GOSUB 400: GOSUB 480: GOSUB
+ 300: IF LO < > 1 THEN 1500
+ 1040 IF LI < > 0 OR CA = 0 THEN
+ 1120
+ 1050 WW = 0:W = 1.8: IF TI > 12 THEN
+ WW = FN R(1000 * TI) + 1000
+ * TI:W = 1
+ 1060 I = FN R(CA / W) + WW:WW =
+ I: GOSUB 600: GOSUB 400:X =
+ USR (10): PRINT WW$;" ";:X =
+ USR (11):CH$ = "NY": GOSUB
+ 100: IF CH% < > 2 THEN 1120
+
+ 1065 LI = 1:CA = CA - I: IF CA >
+ 0 THEN 1100
+ 1070 GOSUB 400: PRINT T$;:X = USR
+ (12): CALL 2512: PRINT : PRINT
+ :X = USR (13):CH$ = "YN": GOSUB
+ 100
+ 1080 IF CH% = 1 THEN DW = DW -
+ CA:CA = 0: GOSUB 400:X = USR
+ (14): CALL 2521: GOSUB 94
+ 1090 IF CH% = 2 THEN CA = 0:LI =
+ 0: GOSUB 400:X = USR (15): PRINT
+ T$;".": CALL 2518: GOSUB 94
+ 1100 GOSUB 300
+ 1120 IF DM = 0 THEN 1210
+ 1130 GOSUB 400: PRINT T$;:X = USR
+ (16):CH$ = "YN": GOSUB 100: IF
+ CH% = 2 THEN 1210
+ 1140 BR = INT (( FN R(60 * (TI +
+ 3) / 4) + 25 * (TI + 3) / 4)
+ * SC / 50)
+ 1142 WW = INT (DM / SC * 100 +
+ .5)
+ 1145 GOSUB 400:X = USR (17): PRINT
+ WW;"% damaged.": PRINT :WW =
+ BR * DM + 1: GOSUB 600:X = USR
+ (18): PRINT WW$;","
+ 1150 X = USR (19): GOSUB 150: IF
+ R1% = 1 THEN W = BR * DM + 1
+ : IF CA < W THEN W = CA
+ 1155 IF CA < W THEN GOSUB 400:
+ PRINT T$;:X = USR (12): GOSUB
+ 96: GOTO 1142
+ 1160 WW = INT (W / BR + .5):DM =
+ DM - WW:CA = CA - W:DM = INT
+ (DM * (DM > 0)): GOSUB 300: GOSUB
+ 400
+ 1210 IF DW < 10000 OR WN OR D =
+ 0 THEN 1300
+ 1220 GOSUB 400: PRINT "Elder Br
+ other Wu has sent "; FN R(10
+ 0) + 50;" braves": PRINT "to
+ escort you to the Wu mansio
+ n, ";T$;".":WN = 1: GOSUB 94
+
+ 1230 GOSUB 400:X = USR (20): GOSUB
+ 92
+ 1240 GOSUB 400:X = USR (21): PRINT
+ T$;".";: GOSUB 92
+ 1300 REM
+ 1310 GOSUB 400:X = USR (22):CH
+ $ = "NY":WU% = 1: GOSUB 100:
+ WU% = 0: IF CH% < > 2 THEN
+ 1500
+ 1320 W = 0: FOR I = 1 TO 2: FOR
+ J = 1 TO 4:W = W + ST(I,J): NEXT
+ J,I: IF CA OR BA OR W OR GN THEN
+ 1360
+ 1330 BL% = BL% + 1:I = INT ( FN
+ R(1500) + 500):J = FN R(200
+ 0) * BL% + 1500: GOSUB 400: PRINT
+ "Elder Brother is aware of y
+ our plight, ";T$;". He is
+ willing to loan you an add
+ itional ";I;" if you will pa
+ y back"
+ 1340 PRINT J;". Are you willing
+ , ";T$;"? ";:CH$ = "YN": GOSUB
+ 100: IF CH% = 2 THEN GOSUB
+ 400: PRINT : PRINT "Very wel
+ l, Taipan, the game is over!
+ ": CALL 2512: GOTO 2698
+ 1350 CA = CA + I:DW = DW + J: GOSUB
+ 400: PRINT "Very well, ";T$;
+ ". Good joss!!": CALL 2521:
+ GOSUB 300: GOSUB 96: GOTO 1
+ 500
+ 1360 IF DW = 0 OR CA = 0 THEN 1
+ 400
+ 1370 GOSUB 400:X = USR (23): GOSUB
+ 150: IF R1% THEN W = CA: IF
+ CA > DW THEN W = DW
+ 1380 IF CA > = W THEN CA = CA -
+ W:DW = DW - W: GOSUB 300: GOTO
+ 1400
+ 1390 PRINT : PRINT : PRINT T$;"
+ , you have only ";CA: PRINT
+ "in cash.": CALL 2518: GOSUB
+ 94: GOTO 1370
+ 1400 GOSUB 400:X = USR (24): GOSUB
+ 150: IF R1% THEN W = 2 * CA
+ 1420 IF CA * 2 > = W THEN CA =
+ CA + W:DW = DW + W: GOSUB 30
+ 0: GOTO 1450
+ 1430 PRINT : PRINT : PRINT "He
+ won't loan you so much, ";T$
+ ;"!": CALL 2518: GOSUB 94: GOTO
+ 1400
+ 1450 REM
+ 1460 IF DW > 20000 AND NOT ( FN
+ R(5)) THEN GOSUB 400: PRINT
+ "Bad joss!!": PRINT FN R(3)
+ + 1;" of your bodyguards ha
+ ve been killed": PRINT "by c
+ utthroats and you have been
+ robbed of all your cash, ";
+ T$;"!!": CALL 2512:CA = 0: GOSUB
+ 300: GOSUB 94
+ 1500 REM
+ 1610 I = INT (1000 + FN R(1000
+ * (TI + 5) / 6)) * ( INT (S
+ C / 50) * (DM > 0) + 1): IF
+ CA < I OR FN R(4) THEN 1700
+
+ 1615 W$ = CHR$ (15) + CHR$ (15
+ ) + "damaged_______" + CHR$ (15) +
+ CHR$ (16) + "fine":WW = I: GOSUB
+ 600
+ 1620 GOSUB 400: PRINT "Do you w
+ ish to trade in your "; MID$
+ (W$,(DM = 0) * 25 + 1,25): PRINT
+ "ship for one with 50 more c
+ apacity by paying an addit
+ ional ";WW$;", ";T$;"? ";
+ 1630 CH$ = "YN": GOSUB 100: IF C
+ H% = 1 THEN CA = CA - I:MW =
+ MW + 50:SC = SC + 50:DM = 0:
+ GOSUB 300
+ 1700 REM
+ 1710 I = INT ( FN R(1000 * (TI +
+ 5) / 6) + 500): IF CA < I OR
+ FN R(3) THEN 1900
+ 1720 WW = I: GOSUB 600: GOSUB 40
+ 0: PRINT "Do you wish to buy
+ a ship's gun": PRINT "for "
+ ;WW$;", ";T$;"? ";:CH$ = "NY
+ ": GOSUB 100: IF CH% = 1 THEN
+ 1900
+ 1730 IF MW > = 10 THEN CA = CA
+ - I:GN = GN + 1:MW = MW - 1
+ 0: GOSUB 300: GOTO 1900
+ 1740 PRINT : PRINT : PRINT "You
+ r ship would be overburdened
+ , ";T$;"!": CALL 2518: GOSUB
+ 94
+ 1900 IF ST(2,1) = 0 OR LO = 1 OR
+ FN R(18) THEN 2000
+ 1910 I = FN R(CA / 1.8):WW = I:
+ GOSUB 600: GOSUB 400: CALL
+ 2512:X = USR (25) + USR (2
+ 6): PRINT WW$;", ";T$;"!":MW
+ = MW + ST(2,1):ST(2,1) = 0:
+ CA = CA - I: GOSUB 300: GOSUB
+ 94
+ 2000 W = 0: FOR J = 1 TO 4:W = W
+ + ST(1,J): NEXT J: IF W = 0
+ OR FN R(50) THEN 2100
+ 2030 GOSUB 400: CALL 2512:X = USR
+ (25) + USR (27): PRINT T$;"
+ !": FOR J = 1 TO 4:W = ST(1,
+ J):WW = FN R(W / 1.8):WS =
+ WS - W + WW:ST(1,J) = WW: NEXT
+ J: GOSUB 300: GOSUB 96
+ 2100 FOR I = 1 TO 4:CP(I) = BP%
+ (LO,I) / 2 * ( FN R(3) + 1) *
+ 10 ^ (4 - I): NEXT I
+ 2310 LI = LI AND FN R(20): IF L
+ I = 0 AND LI% > 0 THEN LI% =
+ LI% + 1: IF LI% > 4 THEN LI%
+ = 0
+ 2330 IF LI = 0 AND LO < > 1 AND
+ FN R(4) THEN GOSUB 400:X =
+ USR (28): CALL 2521: GOSUB
+ 94
+ 2410 IF FN R(9) THEN 2500
+ 2420 GOSUB 400:I = FN R(4) + 1
+ :J = FN R(2):K = FN R(2) *
+ 5: PRINT T$;"!! The price o
+ f ";CO$(I)
+ 2430 IF J = 0 THEN CP(I) = INT
+ (CP(I) / 5): PRINT "has drop
+ ped to ";CP(I);"!!": CALL 25
+ 18
+ 2440 IF J = 1 THEN CP(I) = CP(I
+ ) * ( FN R(5) + 5):WW = CP(I
+ ): GOSUB 600: PRINT "has ris
+ en to ";WW$;"!!": CALL 2518
+ 2450 GOSUB 94
+ 2500 REM
+ 2501 GOSUB 400: IF CA > 25000 AND
+ NOT ( FN R(20)) THEN I = FN
+ R(CA / 1.4):WW = I: GOSUB 60
+ 0:X = USR (25): PRINT "You'
+ ve been beaten up and robbed
+ of": PRINT WW$;" in cash, "
+ ;T$;"!!": CALL 2512:CA = CA -
+ I: GOSUB 300: GOSUB 94: VTAB
+ 22: HTAB 1: PRINT CE$
+ 2510 GOSUB 400: PRINT T$;:X = USR
+ (29)
+ 2515 FOR I = 1 TO 3 STEP 2: PRINT
+ TAB( 4); LEFT$ (CO$(I),7);"
+ : ";CP(I); TAB( 18); LEFT$ (
+ CO$(I + 1),7);": ";CP(I + 1)
+ : NEXT I
+ 2520 I = CA + BA - DW: VTAB 22: HTAB
+ 1: PRINT CE$
+ 2522 IF LO < > 1 THEN X = USR
+ (30):CH$ = "BSQ"
+ 2524 IF LO = 1 AND I < 1E6 THEN
+ X = USR (31) + USR (32):CH
+ $ = "BSQTV"
+ 2526 IF LO = 1 AND I > = 1E6 THEN
+ X = USR (31) + USR (33):CH
+ $ = "BSQTVR"
+ 2528 GOSUB 100: ON CH% GOTO 253
+ 0,2570,2700,2620,2680,2695
+ 2530 VTAB 23: HTAB 1: PRINT CE$
+ ;"What do you wish me to buy
+ , ";T$;"? ";:CH$ = "OSAG": GOSUB
+ 100:CO$ = CO$(CH%):CP = CP(C
+ H%)
+ 2540 VTAB 22: HTAB 1: PRINT CE$
+ ,IV$;: HTAB 31: PRINT " You
+ can ";: VTAB 23: HTAB 31: PRINT
+ " afford ";: VTAB 24: HTAB
+ 31: PRINT " ";:W = INT
+ (CA / CP): IF W > 1E9 THEN W
+ = 1E9 - 1
+ 2542 HTAB 36 - LEN ( STR$ (W))
+ / 2: PRINT W;NV$;: VTAB 23:
+ HTAB 1: PRINT "How much ";C
+ O$;" shall": PRINT "I buy, "
+ ;T$;"? ";: GOSUB 150: IF R1%
+ THEN W = INT (CA / CP): IF
+ W > 1E9 THEN W = 1E9 - 1
+ 2550 IF W < 0 OR CA < W * CP THEN
+ CALL 2524: GOTO 2540
+ 2560 MW = MW - W:CA = CA - W * C
+ P:ST(2,CH%) = ST(2,CH%) + W:
+ GOSUB 300: VTAB 22: HTAB 1:
+ CALL - 958: GOTO 2520
+ 2570 VTAB 23: HTAB 1: PRINT CE$
+ ;"What do you wish me to sel
+ l, ";T$;"? ";:CH$ = "OSAG": GOSUB
+ 100:CO$ = CO$(CH%):CP = CP(C
+ H%)
+ 2580 VTAB 22: HTAB 1: PRINT CE$
+ : PRINT "How much ";CO$;" sh
+ all": PRINT "I sell, ";T$;"?
+ ";: GOSUB 150: IF R1% THEN
+ W = ST(2,CH%)
+ 2590 IF W < 0 OR ST(2,CH%) < W THEN
+ CALL 2524: GOTO 2580
+ 2600 MW = MW + W:CA = CA + W * C
+ P:ST(2,CH%) = ST(2,CH%) - W:
+ GOSUB 300: VTAB 22: HTAB 1:
+ PRINT CE$;: GOTO 2520
+ 2620 REM
+ 2622 W = 0: FOR I = 1 TO 2: FOR
+ J = 1 TO 4:W = W + ST(I,J): NEXT
+ J,I: IF W = 0 THEN VTAB 22:
+ HTAB 1: PRINT CE$;"You have
+ no cargo, ";T$;".": CALL 25
+ 18: GOSUB 94: GOTO 2520
+ 2624 FOR J = 1 TO 4: FOR K = 1 TO
+ 2:I = 3 - K: IF ST(I,J) = 0 THEN
+ 2634
+ 2626 GOSUB 400: PRINT "How much
+ ";CO$(J);" shall I move": PRINT
+ MID$ ("to the warehouseaboa
+ rd ship",K * 16 - 15,16);",
+ ";T$;"? ";: GOSUB 150: IF R1
+ % THEN W = ST(I,J): IF W > (
+ WC - WS) AND K = 1 THEN W =
+ (WC - WS)
+ 2627 IF K = 2 THEN 2630
+ 2628 IF W > 0 AND WS = WC THEN
+ PRINT : PRINT : PRINT "Your
+ warehouse is full, ";T$;"!"
+ : CALL 2518: GOSUB 94: GOTO
+ 2626
+ 2629 IF W > (WC - WS) THEN PRINT
+ : PRINT : PRINT "Your wareho
+ use will only hold an": PRINT
+ "additional ";WC - WS;", ";T
+ $;"!";: CALL 2518: GOSUB 94:
+ GOTO 2626
+ 2630 IF W > ST(I,J) THEN PRINT
+ : PRINT : PRINT "You have on
+ ly ";ST(I,J);", ";T$;".": CALL
+ 2518: GOSUB 94: GOTO 2626
+ 2632 ST(I,J) = ST(I,J) - W:ST(K,
+ J) = ST(K,J) + W:MW = MW + SGN
+ (I - K) * W:WS = WS + SGN (
+ I - K) * W: GOSUB 300
+ 2634 NEXT K,J: GOTO 2500
+ 2680 REM
+ 2690 GOSUB 500: GOTO 2500
+ 2695 OK = 16
+ 2696 GOSUB 400: PRINT IV$; TAB(
+ 26): PRINT : PRINT " Y o u '
+ r e a"; TAB( 26): PRINT
+ : PRINT TAB( 26): PRINT : PRINT
+ " M I L L I O N A I R E ! ":
+ PRINT TAB( 26): PRINT NV$:
+ GOSUB 96
+ 2698 : GOSUB 20000
+ 2699 PRINT "Play again? ";:CH$ =
+ "NY": GOSUB 100: ON CH% GOTO
+ 63999: RUN
+ 2700 REM
+ 2810 IF MW < 0 THEN GOSUB 400:
+ PRINT "You're ship is overl
+ oaded, ";T$;"!!": CALL 2518:
+ GOSUB 94: GOTO 2500
+ 3010 GOSUB 400: PRINT T$;", do
+ you wish to go to:": PRINT "
+ 1) Hong Kong, 2) Shanghai, 3
+ ) Nagasaki, 4) Saigon, 5) Ma
+ nila, 6) Singapore, or 7) B
+ atavia ? ";
+ 3020 CH$ = "1234567": GOSUB 100:
+ D = CH%: IF D = LO THEN PRINT
+ : PRINT : PRINT "You're alre
+ ady here, ";T$;".";: CALL 25
+ 18: GOSUB 94: GOTO 3010
+ 3030 LO = 0: GOSUB 300: GOSUB 40
+ 0: GOSUB 490
+ 3100 REM
+ 3110 IF FN R(BP) THEN 3200
+ 3120 SN = FN R(SC / 10 + GN) +
+ 1: GOSUB 400: CALL 2512: PRINT
+ SN;" hostile ship"; MID$ ("s
+ ",(SN = 1) + 1,1);" approach
+ ing, ";T$;"!!": GOSUB 96:F1 =
+ 1: GOTO 5000
+ 3200 REM
+ 3210 IF FN R(4 + 8 * LI) THEN
+ 3300
+ 3220 GOSUB 400: PRINT "Li Yuen'
+ s pirates, ";T$;"!!": CALL 2
+ 521: GOSUB 94: IF LI THEN PRINT
+ : PRINT "Good joss!! They le
+ t us be!!": CALL 2521: GOSUB
+ 94: GOTO 3300
+ 3230 SN = FN R(SC / 5 + GN) + 5
+ : GOSUB 400: PRINT SN;" ship
+ s of Li Yuen's pirate": PRINT
+ "fleet, ";T$;"!!": CALL 2512
+ : GOSUB 94:F1 = 2: GOTO 5000
+
+ 3300 REM
+ 3310 IF FN R(10) THEN 3350
+ 3320 GOSUB 400: PRINT "Storm, "
+ ;T$;"!!": CALL 2521: GOSUB 9
+ 4: IF NOT ( FN R(30)) THEN
+ PRINT : PRINT " I think w
+ e're going down!!": CALL 252
+ 1: GOSUB 94: IF FN R(DM / S
+ C * 3) THEN PRINT : PRINT "
+ We're going down, Taipan!!":
+ CALL 2512:OK = 1: GOTO 2698
+
+ 3330 PRINT : PRINT " We made
+ it!!": CALL 2521: GOSUB 94:
+ IF FN R(3) THEN 3350
+ 3340 LO = FN R(7) + 1: ON (LO =
+ D) GOTO 3340: GOSUB 400: PRINT
+ "We've been blown off course
+ ": PRINT "to ";LO$(LO):D = L
+ O: GOSUB 94
+ 3350 LO = D: GOTO 1000
+ 5000 REM
+ 5030 LC = 0:CMD = 0: PRINT FS$;H
+ M$
+ 5050 VTAB 1: HTAB 1: PRINT "
+ ships attacking, ";T$;"!":
+ VTAB 1: HTAB 32: PRINT CG$;
+ "!": VTAB 2: HTAB 32: PRINT
+ "!": VTAB 3: HTAB 32: PRINT
+ "<::::::::";CS$: VTAB 2: HTAB
+ 37: PRINT "guns": VTAB 1: HTAB
+ 34: PRINT "We have";
+ 5060 PRINT "Your orders are to:
+ "
+ 5080 FOR I = 0 TO 9:AM%(I,0) =
+ 0:AM%(I,1) = 0: NEXT I:SA =
+ SN:S0 = SN:BT = FN R(TI / 4
+ * 1000 * SN ^ 1.05) + FN R
+ (1000) + 250:SS = 0
+ 5090 REM
+ 5100 GOSUB 5760: GOSUB 5700:LC =
+ CMD: VTAB 12: HTAB 40: PRINT
+ MID$ ("+ ", NOT (SA) + 1,1)
+
+ 5160 DM = INT (DM):WW = 100 - INT
+ (DM / SC * 100): IF WW < 0 THEN
+ WW = 0
+ 5162 VTAB 4: PRINT "Current sea
+ worthiness: ";ST$( INT (WW /
+ 20));" (";WW;"%)": GOSUB 560
+ 0: VTAB 4: PRINT CL$
+ 5165 IF WW = 0 THEN OK = 0: GOTO
+ 5900
+ 5175 GOSUB 5600
+ 5180 ON CMD GOTO 5200,5300,5400
+
+ 5190 VTAB 4: PRINT T$;", what s
+ hall we do??": CALL 2512: GOSUB
+ 5600: ON (CMD = 0) + 1 GOTO
+ 5500,5180
+ 5200 REM
+ 5205 VTAB 4: HTAB 1: PRINT CL$:
+ VTAB 4: PRINT "Aye, we'll r
+ un, ";T$;"!": GOSUB 96: VTAB
+ 4: PRINT CL$
+ 5207 IF LC = 1 OR LC = 3 THEN O
+ K = OK + IK:IK = IK + 1
+ 5208 IF LC = 0 OR LC = 2 THEN O
+ K = 3:IK = 1
+ 5210 IF FN R(OK) > FN R(SN) THEN
+ VTAB 4: PRINT "We got away
+ from 'em, ";T$;"!!": CALL 25
+ 18: GOSUB 96: VTAB 4: PRINT
+ CL$:OK = 3: GOTO 5900
+ 5220 VTAB 4: PRINT "Can't lose
+ 'em!!": GOSUB 5600: VTAB 4: PRINT
+ CL$
+ 5230 IF SN > 2 AND FN R(5) = 0
+ THEN W = FN R(SN / 2) + 1:
+ SN = SN - W:SA = SA - W: GOSUB
+ 5680: GOSUB 5750: VTAB 4: PRINT
+ "But we escaped from ";W;" o
+ f 'em, ";T$;"!": GOSUB 5600:
+ VTAB 4: PRINT CL$
+ 5240 GOTO 5500
+ 5300 REM
+ 5302 IF GN = 0 THEN VTAB 4: HTAB
+ 1: PRINT "We have no guns, "
+ ;T$;"!!": GOSUB 5600: VTAB 4
+ : PRINT CL$: GOTO 5500
+ 5305 VTAB 4: HTAB 1: PRINT CL$:
+ VTAB 4: PRINT "Aye, we'll f
+ ight 'em, ";T$;"!": GOSUB 56
+ 00: VTAB 4: PRINT CL$
+ 5310 SK = 0: VTAB 4: PRINT "We'r
+ e firing on 'em, ";T$;"!": FOR
+ K = 1 TO GN: IF SN = 0 THEN
+ 5340
+ 5320 I = FN R(10): IF AM%(I,0) =
+ 0 THEN 5320
+ 5330 GOSUB 5840:AM%(I,1) = AM%(
+ I,1) + FN R(30) + 10: IF AM
+ %(I,1) > AM%(I,0) THEN AM%(I
+ ,0) = 0:AM%(I,1) = 0: GOSUB
+ 5860: GOSUB 5820:SK = SK + 1
+ :SN = SN - 1:SS = SS - 1: GOSUB
+ 5750: IF SS = 0 THEN GOSUB
+ 5700
+ 5340 NEXT K: IF SK > 0 THEN VTAB
+ 4: HTAB 1: PRINT "Sunk ";SK;
+ " of the buggers, ";T$;"!": CALL
+ 2521: GOSUB 5600: VTAB 4: PRINT
+ CL$
+ 5350 IF SK = 0 THEN VTAB 4: HTAB
+ 1: PRINT "Hit 'em, but didn'
+ t sink 'em, ";T$;"!": GOSUB
+ 5600: VTAB 4: PRINT CL$
+ 5360 IF FN R(S0) < SN * .6 / F
+ 1 OR SN = 0 OR SN = S0 OR SN
+ < 3 THEN 5500
+ 5362 W = FN R(SN / 3 / F1) + 1:
+ SN = SN - W:SA = SA - W: GOSUB
+ 5680
+ 5390 VTAB 4: PRINT W;" ran away
+ , ";T$;"!": GOSUB 5750: CALL
+ 2521: GOSUB 5600: VTAB 4: PRINT
+ CL$: GOTO 5500
+ 5400 REM
+ 5410 GOSUB 400: PRINT "You have
+ the following on board, ";T
+ $;":";: FOR J = 1 TO 4: VTAB
+ 20 + (J = 3 OR J = 4): HTAB
+ 1 + 19 * (J = 2 OR J = 4): PRINT
+ RIGHT$ (" " + LEFT$
+ (CO$(J),7),9);": ";ST(2,J): NEXT
+ J
+ 5420 VTAB 4: PRINT "What shall
+ I throw overboard, ";T$;"? "
+ ;:CH$ = "OSAG*": GOSUB 100: VTAB
+ 4: HTAB 1: PRINT CL$
+ 5430 IF CH% = 5 THEN II = 1:IJ =
+ 4:IK = 1E9: GOTO 5450
+ 5440 VTAB 4: PRINT "How much, "
+ ;T$;"? ";: GOSUB 150:II = CH
+ %:IJ = CH%: IF R1% THEN W =
+ ST(2,II)
+ 5450 WW = 0: FOR J = II TO IJ:IK
+ = ST(2,J): IF W > IK THEN W
+ = IK
+ 5460 ST(2,J) = ST(2,J) - W:WW =
+ WW + W:MW = MW + W: NEXT J: VTAB
+ 4: HTAB 1: PRINT CL$
+ 5470 IF WW = 0 THEN VTAB 4: PRINT
+ "There's nothing there, ";T$
+ ;"!": CALL 2518: GOSUB 5600:
+ VTAB 4: PRINT CL$
+ 5480 GOSUB 400: IF WW > 0 THEN
+ RF = RF + WW / 3:OK = OK + W
+ W / 10: VTAB 4: PRINT "Let's
+ hope we lose 'em, ";T$;"!":
+ CALL 2521: GOSUB 5600: VTAB
+ 4: PRINT CL$: GOTO 5210
+ 5500 REM
+ 5505 IF SN = 0 THEN VTAB 4: PRINT
+ "We got 'em all, ";T$;"!!": CALL
+ 2521: GOSUB 5600:OK = 1: GOTO
+ 5900
+ 5510 VTAB 4: PRINT "They're fir
+ ing on us, ";T$;"!": GOSUB 5
+ 600: VTAB 4: PRINT CL$
+ 5540 FOR I = 1 TO 10: POKE - 1
+ 6298,0: POKE - 16299,0: POKE
+ - 16297,0: POKE - 16300,0:
+ FOR J = 1 TO 10: NEXT J,I
+ 5542 VTAB 4: PRINT "We've been
+ hit, ";T$;"!!": CALL 2512
+ 5545 I = SN: IF I > 15 THEN I =
+ 15
+ 5550 IF GN THEN IF FN R(100) <
+ (DM / SC) * 100 OR (DM / SC)
+ * 100 > 80 THEN I = 1: GOSUB
+ 5600: VTAB 4: PRINT CL$: VTAB
+ 4: PRINT "The buggers hit a
+ gun, ";T$;"!!": CALL 2512:GN
+ = GN - 1:MW = MW + 10: GOSUB
+ 5600: VTAB 4: PRINT CL$
+ 5555 DM = DM + FN R(ED * I * F1
+ ) + I / 2
+ 5560 IF NOT ( FN R(20)) AND F1
+ = 1 THEN OK = 2: GOTO 5900
+ 5590 GOTO 5090
+ 5600 VTAB 2: HTAB 21: FOR II =
+ 1 TO T / 3
+ 5610 W = PEEK ( - 16384): IF W <
+ 128 THEN NEXT II: PRINT : RETURN
+
+ 5620 IF W = 210 THEN CMD = 1: PRINT
+ "Run "
+ 5630 IF W = 198 THEN CMD = 2: PRINT
+ "Fight "
+ 5640 IF W = 212 THEN CMD = 3: PRINT
+ "Throw cargo"
+ 5650 POKE - 16368,0: PRINT
+ 5670 RETURN
+ 5680 IF SA > = 0 THEN RETURN
+
+ 5681 I = 9: FOR IJ = SA TO - 1
+ 5682 IF AM%(I,0) = 0 THEN I = I
+ - 1: GOTO 5682
+ 5683 AM%(I,0) = 0:AM%(I,1) = 0: GOSUB
+ 5880: GOSUB 5820:I = I - 1:S
+ S = SS - 1: NEXT IJ: RETURN
+
+ 5700 REM
+ 5710 FOR I = 0 TO 9: IF AM%(I,0
+ ) THEN 5740
+ 5720 SA = SA - 1: IF SA < 0 THEN
+ SA = 0: RETURN
+ 5730 AM%(I,0) = FN R(EC) + 20:A
+ M%(I,1) = 0: GOSUB 5800:SS =
+ SS + 1
+ 5740 NEXT I: RETURN
+ 5750 REM
+ 5760 VTAB 1: HTAB 1: PRINT RIGHT$
+ (" " + STR$ (SN),4)
+ 5770 VTAB 2: HTAB 33: PRINT RIGHT$
+ (" " + STR$ (GN),3): RETURN
+
+ 5800 GOSUB 5880: HTAB X: VTAB Y
+ : PRINT SH$: RETURN
+ 5820 GOSUB 5880: HTAB X: VTAB Y
+ : PRINT SB$: RETURN
+ 5840 GOSUB 5880: POKE 2493,(Y +
+ 4) * 8 - 1: POKE 2494,X - 1:
+ FOR J = 0 TO 1:IJ = FN R(6
+ ):II = DL%(IJ,J): HTAB X + INT
+ (II / 10): VTAB Y + II - INT
+ (II / 10) * 10: PRINT DM$(IJ
+ ,J): NEXT J: CALL 2368: RETURN
+
+ 5860 GOSUB 5880: POKE 2361,(Y +
+ 4) * 8 - 1: POKE 2362,X - 1:
+ POKE 2300, FN R( FN R(192))
+ : CALL 2224: RETURN
+ 5880 X = (I - INT (I / 5) * 5) *
+ 8 + 1:Y = INT (I / 5) * 6 +
+ 7: RETURN
+ 5900 GOSUB 200: GOSUB 300: GOSUB
+ 400
+ 5910 IF OK = 0 THEN PRINT "The
+ buggers got us, ";T$;"!!!":
+ PRINT "It's all over, now!!
+ !":OK = 1: GOTO 2698
+ 5920 IF OK = 1 THEN GOSUB 400:
+ PRINT "We've captured some
+ booty":WW = BT: GOSUB 600: PRINT
+ "It's worth ";WW$;"!": CALL
+ 2518:CA = CA + BT: GOSUB 96:
+ GOTO 3300
+ 5930 IF OK = 2 THEN PRINT "Li
+ Yuen's fleet drove them off!
+ ": GOSUB 96: GOTO 3220
+ 5940 IF OK = 3 THEN PRINT "We
+ made it, ";T$;"!": CALL 2518
+ : GOSUB 96: GOTO 3300
+ 10000 REM
+ 10010 CALL 6147: POKE 1013,76: POKE
+ 1014,224: POKE 1015,9: POKE
+ 10,76: POKE 11,16: POKE 12,1
+ 1: POKE 1010,102: POKE 1011,
+ 213: POKE 1012,112: DIM LO$(
+ 7),CO$(4),CP(4),BP%(7,4),ST(
+ 2,4),AM%(9,1),DM$(5,1),DL%(5
+ ,1),ST$(5)
+ 10020 DEF FN R(X) = INT ( USR
+ (0) * X)
+ 10040 HM$ = CHR$ (16):CS$ = CHR$
+ (1) + "0":CA$ = CHR$ (1) +
+ "1":CG$ = CHR$ (1) + "2":BD
+ $ = CHR$ (2):CD$ = CHR$ (3
+ ):DD$ = CHR$ (4):IV$ = CHR$
+ (9):NV$ = CHR$ (14):FS$ = CHR$
+ (25):CE$ = CHR$ (6):CL$ = CHR$
+ (5)
+ 10045 IF PEEK (2367) = 236 THEN
+ 10070
+ 10050 POKE - 16368,0
+ 10060 FOR I = 1 TO 400:CH% = PEEK
+ ( - 16384):X = USR (0): IF
+ CH% < 128 THEN NEXT
+ 10062 VTAB 20: HTAB 31: PRINT I
+ V$;CA$;"'ESC'";: FOR I = 1 TO
+ 20:X = USR (0): IF PEEK ( -
+ 16384) < > 155 THEN NEXT :
+ VTAB 20: HTAB 31: PRINT NV$
+ ;CA$ + "'ESC'";: FOR I = 1 TO
+ 20:X = USR (0): IF PEEK ( -
+ 16384) < > 155 THEN NEXT :
+ GOTO 10062
+ 10070 POKE 2367,236: POKE - 16
+ 368,0: PRINT NV$;FS$;HM$
+ 10110 VTAB 8: HTAB 1: PRINT CG$
+ ;"[";: & 45,38: PRINT "]";: FOR
+ I = 1 TO 8: PRINT "!"; TAB(
+ 40);"!";: NEXT I: PRINT "<";
+ : & 58,38: PRINT ">";CS$
+ 10120 VTAB 10: HTAB 7: PRINT CS
+ $;T$;",": VTAB 12: HTAB 3: PRINT
+ "What will you name your": VTAB
+ 15: HTAB 13: & 45,22: VTAB 1
+ 4: HTAB 7: PRINT "Firm: ";CA
+ $;: & 32,27: VTAB 14: HTAB 1
+ 3: POKE 33,39: CALL 2200: POKE
+ 33,40:WK$ = MID$ (WK$,1): IF
+ WK$ = "" THEN CALL 2521: GOTO
+ 10120
+ 10130 IF LEN (WK$) > 22 THEN PRINT
+ : VTAB 18: PRINT IV$;: & 32,
+ 42: PRINT "Please limit your
+ Firm's name to 22 chara
+ cters or less.";: & 32,59: PRINT
+ NV$: CALL 2518: GOSUB 92: VTAB
+ 18: PRINT CE$: GOTO 10120
+ 10140 H$ = WK$: PRINT HM$;CS$: VTAB
+ 6: PRINT "Do you want to sta
+ rt . . .": PRINT : PRINT : PRINT
+ " 1) With cash (and a debt)
+ ": PRINT : PRINT : PRINT ,">
+ > or <<": PRINT : PRINT : PRINT
+ " 2) With five guns and no
+ cash": PRINT ,"(But no debt!
+ )"
+ 10150 PRINT : PRINT : PRINT TAB(
+ 10);" ?";:CH$ = "12": GOSUB
+ 100:MO = 1:YE = 1860:SC = 60
+ :BA = 0:LO = 1:TI = 1:WC = 1
+ 0000:WS = 0
+ 10160 IF CH% = 1 THEN DW = 5000
+ :CA = 400:MW = 60:GN = 0:BP =
+ 10
+ 10170 IF CH% = 2 THEN DW = 0:CA
+ = 0:MW = 10:GN = 5:BP = 7
+ 10180 FOR I = 0 TO 7: READ LO$(
+ I): NEXT I: DATA At sea,Hong
+ Kong,Shanghai,Nagasaki,Saig
+ on,Manila,Singapore,Batavia
+ 10190 FOR I = 1 TO 4: READ CO$(
+ I): FOR J = 1 TO 7: READ BP%
+ (J,I): NEXT J,I
+ 10200 DATA Opium,11,16,15,14,1
+ 2,10,13,Silk,11,14,15,16,10,
+ 13,12,Arms,12,16,10,11,13,14
+ ,15,General Cargo,10,11,12,1
+ 3,14,15,16
+ 10210 FOR I = 0 TO 5: READ ST$(
+ I): NEXT I: DATA "Critical",
+ " Poor"," Fair"," Good","
+ Prime","Perfect"
+ 10250 SH$ = BD$ + CG$ + "ABCDEFG
+ " + CD$ + "HIJKLMN" + CD$ +
+ "OIJKLPQ" + CD$ + "RSTUVWX" +
+ CD$ + "YJJJJJZ" + DD$
+ 10260 SB$ = BD$: FOR II = 1 TO 5
+ :SB$ = SB$ + " " + CD$
+ : NEXT II:SB$ = SB$ + DD$
+ 10270 FOR I = 0 TO 5: FOR J = 0
+ TO 1:CH$ = BD$ + CG$
+ 10280 READ WK$:CH$ = CH$ + WK$:
+ IF RIGHT$ (CH$,1) = "*" THEN
+ CH$ = MID$ (CH$,1, LEN (CH$
+ ) - 1) + CD$: GOTO 10280
+ 10290 DM$(I,J) = CH$ + DD$: READ
+ DL%(I,J): NEXT J,I
+ 10300 DATA cde,20,r,3,fg*,mn,50
+ ,tu,23,ij,11,vw,43,0,22,x*,z
+ ,63,kl,32,12,14,pq,52,345,34
+
+ 10310 EC = 20:ED = .5
+ 10990 GOSUB 200: GOTO 1000
+ 20000 REM
+ 20010 WW = CA + BA - DW: GOSUB 6
+ 00:WW = INT ((CA + BA - DW)
+ / 100 / TI ^ 1.1)
+ 20020 PRINT FS$;HM$;CS$;: PRINT
+ "Your final status:": PRINT
+ : PRINT "Net Cash: ";WW$: PRINT
+ : PRINT "Ship size: ";SC;" u
+ nits with ";GN;" guns": PRINT
+
+ 20030 PRINT "You traded for "; INT
+ (TI / 12);" year"; MID$ ("s"
+ ,(TI > 11 AND TI < 24) + 1,1
+ );" and ";TI - INT (TI / 12
+ ) * 12;" month"; MID$ ("s",(
+ (TI - INT (TI / 12) * 12) =
+ 1) + 1,1): PRINT : PRINT IV$
+ ;"Your score is ";WW;".";NV$
+
+ 20040 VTAB 14: PRINT "Your Rati
+ ng:": PRINT CG$;"[";: & 45,3
+ 1: PRINT "]": FOR I = 1 TO 5
+ : PRINT "!";: HTAB 33: PRINT
+ "!": NEXT I: PRINT "<";: & 5
+ 8,31: PRINT ">";CS$: VTAB 16
+
+ 20050 HTAB 2: IF WW > 49999 THEN
+ PRINT IV$;
+ 20060 PRINT "Ma Tsu";NV$;"
+ 50,000 and over "
+ 20070 HTAB 2: IF WW < 50000 AND
+ WW > 7999 THEN PRINT IV$;
+ 20080 PRINT "Master ";T$;NV$;"
+ 8,000 to 49,999"
+ 20090 HTAB 2: IF WW < 8000 AND
+ WW > 999 THEN PRINT IV$;
+ 20100 PRINT T$;NV$;" 1
+ ,000 to 7,999"
+ 20110 HTAB 2: IF WW < 1000 AND
+ WW > 499 THEN PRINT IV$;
+ 20120 PRINT "Compradore";NV$;"
+ 500 to 999"
+ 20130 HTAB 2: IF WW < 500 THEN
+ PRINT IV$;
+ 20140 PRINT "Galley Hand";NV$;"
+ less than 500"
+ 20170 VTAB 11
+ 20180 IF WW < 99 AND WW > = 0 THEN
+ PRINT "Have you considered
+ a land based job?": PRINT
+ 20190 IF WW < 0 THEN PRINT "Th
+ e crew has requested that yo
+ u stay on shore for their sa
+ fety!!": PRINT
+ 20900 VTAB 23: RETURN
+ 63999 PRINT FS$;HM$: TEXT : HOME
+ : POKE 103,1: POKE 104,8: END
+
+
+] \ No newline at end of file
diff --git a/taipan-orig.c b/taipan-orig.c
new file mode 100644
index 0000000..2b0bc71
--- /dev/null
+++ b/taipan-orig.c
@@ -0,0 +1,2735 @@
+/* ------------------------------------------------------------------------ *
+ * Taipan version 0.9
+ * A text/ncurses game for Linux.
+ *
+ * Created by:
+ * Art Canfil
+ *
+ * Programmed by:
+ * Jay Link <jlink@ilbbs.com>
+ *
+ * Apple ][ program coded by:
+ * Ronald J. Berg
+ * ------------------------------------------------------------------------ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <curses.h>
+
+#define GENERIC 1
+#define LI_YUEN 2
+
+void splash_intro(void);
+int get_one(void);
+long get_num(int maxlen);
+void name_firm(void);
+void cash_or_guns(void);
+void set_prices(void);
+void port_stats(void);
+int port_choices(void);
+void new_ship(void);
+void new_gun(void);
+void li_yuen_extortion(void);
+void elder_brother_wu(void);
+void good_prices(void);
+void buy(void);
+void sell(void);
+void visit_bank(void);
+void transfer(void);
+void quit(void);
+void overload(void);
+void fancy_numbers(float num, char *fancy);
+int sea_battle(int id, int num_ships);
+void draw_lorcha(int x, int y);
+void clear_lorcha(int x, int y);
+void draw_blast(int x, int y);
+void sink_lorcha(int x, int y);
+void fight_stats(int ships, int orders);
+void mchenry(void);
+void retire(void);
+void final_stats(void);
+
+char firm[23],
+ fancy_num[13];
+
+char *item[] = { "Opium", "Silk", "Arms", "General Cargo" };
+
+char *location[] = { "At sea", "Hong Kong", "Shanghai", "Nagasaki",
+ "Saigon", "Manila", "Singapore", "Batavia" };
+
+char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+char *st[] = { "Critical", " Poor", " Fair",
+ " Good", " Prime", "Perfect" };
+
+float cash = 0,
+ bank = 0,
+ debt = 0,
+ booty = 0,
+ ec = 20,
+ ed = .5;
+
+long price[4];
+
+int base_price[4][8] = { {1000, 11, 16, 15, 14, 12, 10, 13},
+ {100, 11, 14, 15, 16, 10, 13, 12},
+ {10, 12, 16, 10, 11, 13, 14, 15},
+ {1, 10, 11, 12, 13, 14, 15, 16} };
+
+int hkw_[4],
+ hold_[4];
+
+int hold = 0,
+ capacity = 60,
+ guns = 0,
+ bp = 0,
+ damage = 0,
+ month = 1,
+ year = 1860,
+ li = 0,
+ port = 1,
+ wu_warn = 0,
+ wu_bailout = 0;
+
+int main(void)
+{
+ int choice;
+
+ srand(getpid());
+
+ initscr();
+ cbreak();
+ noecho();
+
+ splash_intro();
+ name_firm();
+ cash_or_guns();
+ set_prices();
+
+ for (;;)
+ {
+ choice = 0;
+
+ port_stats();
+
+ if ((port == 1) && (li == 0) && (cash > 0))
+ {
+ li_yuen_extortion();
+ }
+
+ if ((port == 1) && (damage > 0))
+ {
+ mchenry();
+ }
+
+ if ((port == 1) && (debt >= 10000) && (wu_warn == 0))
+ {
+ int braves = rand()%100 + 50;
+
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Elder Brother Wu has sent %d braves\n", braves);
+ printw("to escort you to the Wu mansion, Taipan.\n");
+
+ refresh();
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ move(18, 0);
+ clrtobot();
+ printw("Elder Brother Wu reminds you of the\n");
+ printw("Confucian ideal of personal worthiness,\n");
+ printw("and how this applies to paying one's\n");
+ printw("debts.\n");
+
+ refresh();
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ move(18, 0);
+ clrtobot();
+ printw("He is reminded of a fabled barbarian\n");
+ printw("who came to a bad end, after not caring\n");
+ printw("for his obligations.\n\n");
+ printw("He hopes no such fate awaits you, his\n");
+ printw("friend, Taipan.\n");
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+
+ wu_warn = 1;
+ }
+
+ if (port == 1)
+ {
+ elder_brother_wu();
+ }
+
+ if (rand()%4 == 0)
+ {
+ if (rand()%2 == 0)
+ {
+ new_ship();
+ } else if (guns < 1000) {
+ new_gun();
+ }
+ }
+
+ if ((port != 1) && (rand()%18 == 0) && (hold_[0] > 0))
+ {
+ float fine = ((cash / 1.8) * ((float) rand() / RAND_MAX)) + 1;
+
+ hold += hold_[0];
+ hold_[0] = 0;
+ cash -= fine;
+
+ port_stats();
+
+ fancy_numbers(fine, fancy_num);
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Bad Joss!!\n");
+ printw("The local authorities have seized your\n");
+ printw("Opium cargo and have also fined you\n");
+ printw("%s, Taipan!\n", fancy_num);
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+
+ if ((rand()%50 == 0) &&
+ ((hkw_[0] + hkw_[1] + hkw_[2] + hkw_[3]) > 0))
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ hkw_[i] = ((hkw_[i] / 1.8) * ((float) rand() / RAND_MAX));
+ }
+
+ port_stats();
+
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Messenger reports large theft\n");
+ printw("from warehouse, Taipan.\n");
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+
+ if (rand()%20 == 0)
+ {
+ if (li > 0) { li++; }
+ if (li == 4) { li = 0; }
+ }
+
+ if ((port != 1) && (li == 0) && (rand()%4 != 0))
+ {
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Li Yuen has sent a Lieutenant,\n");
+ printw("Taipan. He says his admiral wishes\n");
+ printw("to see you in Hong Kong, posthaste!\n");
+
+ refresh();
+ timeout(3000);
+ getch();
+ timeout(-1);
+ }
+
+ if (rand()%9 == 0)
+ {
+ good_prices();
+ }
+
+ if ((cash > 25000) && (rand()%20 == 0))
+ {
+ float robbed = ((cash / 1.4) * ((float) rand() / RAND_MAX));
+
+ cash -= robbed;
+ port_stats();
+
+ fancy_numbers(robbed, fancy_num);
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Bad Joss!!\n");
+ printw("You've been beaten up and\n");
+ printw("robbed of %s in cash, Taipan!!\n", fancy_num);
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+
+ for (;;)
+ {
+ while ((choice != 'Q') && (choice != 'q'))
+ {
+ switch (choice = port_choices())
+ {
+ case 'B':
+ case 'b':
+ buy();
+ break;
+
+ case 'S':
+ case 's':
+ sell();
+ break;
+
+ case 'V':
+ case 'v':
+ visit_bank();
+ break;
+
+ case 'T':
+ case 't':
+ transfer();
+ break;
+
+ case 'R':
+ case 'r':
+ retire();
+ }
+
+ port_stats();
+ }
+
+ choice = 0;
+ if (hold >= 0)
+ {
+ quit();
+ break;
+ } else {
+ overload();
+ }
+ }
+ }
+
+ clear();
+ refresh();
+ nocbreak();
+ endwin();
+
+ return EXIT_SUCCESS;
+}
+
+void splash_intro(void)
+{
+ flushinp();
+ clear();
+ printw("\n");
+ printw(" _____ _ ___ ____ _ _ _ ===============\n");
+ printw(" |_ _|/ \\ |_ _| _ \\ / \\ | \\ | | Created by:\n");
+ printw(" | | / _ \\ | || |_) / _ \\ | \\| | Art Canfil\n");
+ printw(" | |/ ___ \\ | || __/ ___ \\| |\\ |\n");
+ printw(" |_/_/ \\_\\___|_| /_/ \\_\\_| \\_| ===============\n");
+ printw(" Programmed by:\n");
+ printw(" A game based on the China trade of the 1800's Jay Link\n");
+ printw("\n");
+ printw(" ~~| , jlink@ilbbs.com\n");
+ printw(" ,|`-._/|\n");
+ printw(" .' | /||\\ ===============\n");
+ printw(" .' | ./ ||`\\ Copyright (c)\n");
+ printw(" / `-. |/._ || \\ 1978 - 2002\n");
+ printw(" / `|| `|;-._\\ Art Canfil\n");
+ printw(" | || || \\\n");
+ printw("~^~_-~^~=~^~~^= / || ||__ \\~^=~^~-~^~_~^~= ===============\n");
+ printw(" ~=~^~ _~^~ =~ `--------|`---|| `\"-`___~~^~ =_~^= Press ");
+ attrset(A_REVERSE);
+ printw("ANY");
+ attrset(A_NORMAL);
+ printw(" key\n");
+ printw("~ ~^~=~^_~^~ =~ \\~~~~~~~'~~~~'~~~~/~~`` ~=~^~ ~^= to start.\n");
+ printw(" ~^=~^~_~-=~^~ ^ `--------------'~^~=~^~_~^=~^~=~\n");
+ curs_set(0);
+ refresh();
+
+ getch();
+ curs_set(1);
+ return;
+}
+
+int get_one(void)
+{
+ int input,
+ choice = 0,
+ character = 0;
+
+ while ((input = getch()) != '\n')
+ {
+ if (((input == 8) || (input == 127)) && (character == 0))
+ {
+ refresh();
+ } else if ((input == 8) || (input == 127)) {
+ printw("%c", 8);
+ printw(" ");
+ printw("%c", 8);
+ character--;
+ refresh();
+ } else if (character >= 1) {
+ refresh();
+ } else if (input == '\33') {
+ flushinp();
+ refresh();
+ } else {
+ printw("%c", input);
+ choice = input;
+ character++;
+ refresh();
+ }
+ }
+
+ return choice;
+}
+
+long get_num(int maxlen)
+{
+ char number[maxlen + 1];
+
+ int input,
+ character = 0;
+
+ long amount;
+
+ while ((input = getch()) != '\n')
+ {
+ if (((input == 8) || (input == 127)) && (character == 0))
+ {
+ refresh();
+ } else if ((input == 8) || (input == 127)) {
+ printw("%c", 8);
+ printw(" ");
+ printw("%c", 8);
+ number[character] = '\0';
+ character--;
+ refresh();
+ } else if (character >= maxlen) {
+ refresh();
+ } else if (input == '\33') {
+ flushinp();
+ refresh();
+ } else if (((input == 'A') || (input == 'a')) &&
+ (character == 0) && (maxlen > 1)) {
+ printw("%c", input);
+ number[character] = input;
+ character++;
+ refresh();
+ } else if ((input < 48) || (input > 57)) {
+ refresh();
+ } else {
+ printw("%c", input);
+ number[character] = input;
+ character++;
+ refresh();
+ }
+ }
+
+ number[character] = '\0';
+ if ((strcmp(number, "A") == 0) || (strcmp(number, "a") == 0))
+ {
+ amount = -1;
+ } else {
+ amount = strtol(number, (char **)NULL, 10);
+ }
+
+ return amount;
+}
+
+void name_firm(void)
+{
+ int input,
+ character = 0;
+
+ clear();
+ move (7, 0);
+ printw(" _______________________________________\n");
+ printw("| Taipan, |\n");
+ printw("| |\n");
+ printw("| What will you name your |\n");
+ printw("| |\n");
+ printw("| Firm: |\n");
+ printw("| ---------------------- |\n");
+ printw("|_______________________________________|\n");
+
+ move(12, 12);
+ refresh();
+
+ while (((input = getch()) != '\n') && (character < 22))
+ {
+ if (((input == 8) || (input == 127)) && (character == 0))
+ {
+ refresh();
+ } else if ((input == 8) || (input == 127)) {
+ printw("%c", 8);
+ printw(" ");
+ printw("%c", 8);
+ firm[character] = '\0';
+ character--;
+ refresh();
+ } else if (input == '\33') {
+ flushinp();
+ refresh();
+ } else {
+ printw("%c", input);
+ firm[character] = input;
+ character++;
+ refresh();
+ }
+ }
+
+ firm[character] = '\0';
+
+ return;
+}
+
+void cash_or_guns(void)
+{
+ int choice = 0;
+
+ clear();
+ move (5, 0);
+ printw("Do you want to start . . .\n\n");
+ printw(" 1) With cash (and a debt)\n\n");
+ printw(" >> or <<\n\n");
+ printw(" 2) With five guns and no cash\n");
+ printw(" (But no debt!)\n");
+
+ while ((choice != '1') && (choice != '2'))
+ {
+ move (15, 0);
+ clrtoeol();
+ printw(" ?");
+ refresh();
+ choice = get_one();
+ }
+
+ if (choice == '1')
+ {
+ cash = 400;
+ debt = 5000;
+ hold = 60;
+ guns = 0;
+ li = 0;
+ bp = 10;
+ } else {
+ cash = 0;
+ debt = 0;
+ hold = 10;
+ guns = 5;
+ li = 1;
+ bp = 7;
+ }
+
+ return;
+}
+
+void set_prices(void)
+{
+ price[0] = base_price[0][port] / 2 * (rand()%3 + 1) * base_price[0][0];
+ price[1] = base_price[1][port] / 2 * (rand()%3 + 1) * base_price[1][0];
+ price[2] = base_price[2][port] / 2 * (rand()%3 + 1) * base_price[2][0];
+ price[3] = base_price[3][port] / 2 * (rand()%3 + 1) * base_price[3][0];
+ return;
+}
+
+void port_stats(void)
+{
+ int in_use,
+ status = 100 - (((float) damage / capacity) * 100),
+ spacer,
+ i;
+
+ clear();
+ spacer = 12 - (strlen(firm) / 2);
+ for (i = 1; i <= spacer; i++)
+ {
+ printw(" ");
+ }
+ printw("Firm: %s, Hong Kong\n", firm);
+ printw(" ______________________________________\n");
+ printw("|Hong Kong Warehouse | Date\n");
+ printw("| Opium In Use: |\n");
+ printw("| Silk |\n");
+ printw("| Arms Vacant: | Location\n");
+ printw("| General |\n");
+ printw("|______________________________________|\n");
+ printw("|Hold Guns | Debt\n");
+ printw("| Opium |\n");
+ printw("| Silk |\n");
+ printw("| Arms | Ship Status\n");
+ printw("| General |\n");
+ printw("|______________________________________|\n");
+ printw("Cash: Bank:\n");
+ printw("________________________________________\n");
+
+ move(3, 12);
+ printw("%d", hkw_[0]);
+ move(4, 12);
+ printw("%d", hkw_[1]);
+ move(5, 12);
+ printw("%d", hkw_[2]);
+ move(6, 12);
+ printw("%d", hkw_[3]);
+ move(8, 6);
+ if (hold >= 0)
+ {
+ printw("%d", hold);
+ } else {
+ attrset(A_REVERSE);
+ printw("Overload");
+ attrset(A_NORMAL);
+ }
+ move(9, 12);
+ printw("%d", hold_[0]);
+ move(10, 12);
+ printw("%d", hold_[1]);
+ move(11, 12);
+ printw("%d", hold_[2]);
+ move(12, 12);
+ printw("%d", hold_[3]);
+
+ move(14, 5);
+ fancy_numbers(cash, fancy_num);
+ printw("%s", fancy_num);
+
+ in_use = hkw_[0] + hkw_[1] + hkw_[2] + hkw_[3];
+ move(4, 21);
+ printw("%d", in_use);
+ move(6, 21);
+ printw("%d", (10000 - in_use));
+
+ move(8, 25);
+ printw("%d", guns);
+
+ move(14, 25);
+ fancy_numbers(bank, fancy_num);
+ printw("%s", fancy_num);
+
+ move(3, 42);
+ printw("15 ");
+ attrset(A_REVERSE);
+ printw("%s", months[month - 1]);
+ attrset(A_NORMAL);
+ printw(" %d", year);
+
+ move(6, 43);
+ spacer = (9 - strlen(location[port])) / 2;
+ for (i = 1; i <= spacer; i++)
+ {
+ printw(" ");
+ }
+ attrset(A_REVERSE);
+ printw("%s", location[port]);
+ attrset(A_NORMAL);
+
+ move(9, 41);
+ fancy_numbers(debt, fancy_num);
+ spacer = (12 - strlen(fancy_num)) / 2;
+ for (i = 1; i <= spacer; i++)
+ {
+ printw(" ");
+ }
+ attrset(A_REVERSE);
+ printw("%s", fancy_num);
+ attrset(A_NORMAL);
+
+ i = status / 20;
+ if (i < 2)
+ {
+ attrset(A_REVERSE);
+ move(12, 51);
+ printw(" ");
+ }
+ move(12, 42);
+ printw("%s:%d", st[i], status);
+ attrset(A_NORMAL);
+}
+
+int port_choices(void)
+{
+ int choice = 0;
+
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Taipan, present prices per unit here are\n");
+ printw(" Opium: Silk:\n");
+ printw(" Arms: General:\n");
+ move(19, 11);
+ printw("%ld", price[0]);
+ move(19, 29);
+ printw("%ld", price[1]);
+ move(20, 11);
+ printw("%ld", price[2]);
+ move(20, 29);
+ printw("%ld", price[3]);
+
+ for (;;)
+ {
+ move (22, 0);
+ clrtobot();
+
+ if (port == 1)
+ {
+ if ((cash + bank) >= 1000000)
+ {
+ printw("Shall I Buy, Sell, Visit bank, Transfer\n");
+ printw("cargo, Quit trading, or Retire? ");
+ refresh();
+
+ choice = get_one();
+ if ((choice == 'B') || (choice == 'b') ||
+ (choice == 'S') || (choice == 's') ||
+ (choice == 'V') || (choice == 'v') ||
+ (choice == 'T') || (choice == 't') ||
+ (choice == 'Q') || (choice == 'q') ||
+ (choice == 'R') || (choice == 'r'))
+ {
+ break;
+ }
+ } else {
+ printw("Shall I Buy, Sell, Visit bank, Transfer\n");
+ printw("cargo, or Quit trading? ");
+ refresh();
+
+ choice = get_one();
+ if ((choice == 'B') || (choice == 'b') ||
+ (choice == 'S') || (choice == 's') ||
+ (choice == 'V') || (choice == 'v') ||
+ (choice == 'T') || (choice == 't') ||
+ (choice == 'Q') || (choice == 'q'))
+ {
+ break;
+ }
+ }
+ } else {
+ printw("Shall I Buy, Sell, or Quit trading? ");
+ refresh();
+
+ choice = get_one();
+ if ((choice == 'B') || (choice == 'b') ||
+ (choice == 'S') || (choice == 's') ||
+ (choice == 'Q') || (choice == 'q'))
+ {
+ break;
+ }
+ }
+ }
+
+ return choice;
+}
+
+void buy(void)
+{
+ char space[5];
+
+ int choice = 0;
+
+ long afford,
+ amount;
+
+ for (;;)
+ {
+ move(22, 0);
+ clrtobot();
+
+ printw("What do you wish me to buy, Taipan? ");
+ refresh();
+
+ choice = get_one();
+ if ((choice == 'O') || (choice == 'o'))
+ {
+ choice = 0;
+ break;
+ } else if ((choice == 'S') || (choice == 's')) {
+ choice = 1;
+ break;
+ } else if ((choice == 'A') || (choice == 'a')) {
+ choice = 2;
+ break;
+ } else if ((choice == 'G') || (choice == 'g')) {
+ choice = 3;
+ break;
+ }
+ }
+
+ for (;;)
+ {
+ move(21, 42);
+ clrtobot();
+
+ afford = cash / price[choice];
+ attrset(A_REVERSE);
+ printw(" You can ");
+ attrset(A_NORMAL);
+ move(22, 0);
+ printw("How much %s shall", item[choice]);
+ move(22, 42);
+ attrset(A_REVERSE);
+ printw(" afford ");
+ move(23, 42);
+ printw(" ");
+ move(23, 42);
+ if (afford < 100)
+ {
+ strcpy(space, " ");
+ } else if (afford < 10000) {
+ strcpy(space, " ");
+ } else if (afford < 1000000) {
+ strcpy(space, " ");
+ } else if (afford < 100000000) {
+ strcpy(space, " ");
+ } else {
+ strcpy(space, "");
+ }
+ printw("%s%ld", space, afford);
+ attrset(A_NORMAL);
+
+ move(23, 0);
+ printw("I buy, Taipan: ");
+ refresh();
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = afford;
+ }
+ if (amount <= afford)
+ {
+ break;
+ }
+ }
+
+ cash -= (amount * price[choice]);
+ hold_[choice] += amount;
+ hold -= amount;
+
+ return;
+}
+
+void sell(void)
+{
+ int choice = 0;
+
+ long amount;
+
+ for (;;)
+ {
+ move(22, 0);
+ clrtobot();
+
+ printw("What do you wish me to sell, Taipan? ");
+ refresh();
+
+ choice = get_one();
+ if ((choice == 'O') || (choice == 'o'))
+ {
+ choice = 0;
+ break;
+ } else if ((choice == 'S') || (choice == 's')) {
+ choice = 1;
+ break;
+ } else if ((choice == 'A') || (choice == 'a')) {
+ choice = 2;
+ break;
+ } else if ((choice == 'G') || (choice == 'g')) {
+ choice = 3;
+ break;
+ }
+ }
+
+ for (;;)
+ {
+ move(22, 0);
+ clrtobot();
+
+ printw("How much %s shall\n", item[choice]);
+ printw("I sell, Taipan: ");
+ refresh();
+
+ amount = get_num(9);
+
+ if (amount == -1)
+ {
+ amount = hold_[choice];
+ }
+ if (hold_[choice] >= amount)
+ {
+ hold_[choice] -= amount;
+ break;
+ }
+ }
+
+ cash += (amount * price[choice]);
+ hold += amount;
+
+ return;
+}
+
+void visit_bank(void)
+{
+ long amount = 0;
+
+ for (;;)
+ {
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("How much will you deposit? ");
+ refresh();
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = cash;
+ }
+ if (amount <= cash)
+ {
+ cash -= amount;
+ bank += amount;
+ break;
+ } else {
+ move(18, 0);
+ clrtobot();
+ fancy_numbers(cash, fancy_num);
+ printw("Taipan, you only have %s\n", fancy_num);
+ printw("in cash.\n");
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ port_stats();
+
+ for (;;)
+ {
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("How much will you withdraw? ");
+ refresh();
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = bank;
+ }
+ if (amount <= bank)
+ {
+ cash += amount;
+ bank -= amount;
+ break;
+ } else {
+ fancy_numbers(cash, fancy_num);
+ printw("Taipan, you only have %s\n", fancy_num);
+ printw("in the bank.");
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ port_stats();
+
+ return;
+}
+
+void transfer(void)
+{
+ int i, in_use;
+
+ long amount = 0;
+
+ if ((hkw_[0] == 0) && (hold_[0] == 0) &&
+ (hkw_[1] == 0) && (hold_[1] == 0) &&
+ (hkw_[2] == 0) && (hold_[2] == 0) &&
+ (hkw_[3] == 0) && (hold_[3] == 0))
+ {
+ move(22, 0);
+ clrtobot();
+ printw("You have no cargo, Taipan.\n");
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ return;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ if (hold_[i] > 0)
+ {
+ for (;;)
+ {
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("How much %s shall I move\n", item[i]);
+ printw("to the warehouse, Taipan? ");
+ refresh();
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = hold_[i];
+ }
+ if (amount <= hold_[i])
+ {
+ in_use = hkw_[0] + hkw_[1] + hkw_[2] + hkw_[3];
+ if ((in_use + amount) <= 10000)
+ {
+ hold_[i] -= amount;
+ hkw_[i] += amount;
+ hold += amount;
+ break;
+ } else if (in_use == 10000) {
+ move (21, 0);
+ printw("Your warehouse is full, Taipan!");
+ } else {
+ move (21, 0);
+ printw("Your warehouse will only hold an\n");
+ printw("additional %d, Taipan!", (10000 - in_use));
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ } else {
+ move(18, 0);
+ clrtobot();
+ printw("You have only %d, Taipan.\n", hold_[i]);
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ port_stats();
+ }
+
+ if (hkw_[i] > 0)
+ {
+ for (;;)
+ {
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("How much %s shall I move\n", item[i]);
+ printw("aboard ship, Taipan? ");
+ refresh();
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = hkw_[i];
+ }
+ if (amount <= hkw_[i])
+ {
+ hold_[i] += amount;
+ hkw_[i] -= amount;
+ hold -= amount;
+ break;
+ } else {
+ move(18, 0);
+ clrtobot();
+ printw("You have only %d, Taipan.\n", hkw_[i]);
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ port_stats();
+ }
+ }
+
+ return;
+}
+
+void quit(void)
+{
+ int choice = 0,
+ result = 0;
+
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Taipan, do you wish me to go to:\n");
+ printw("1) Hong Kong, 2) Shanghai, 3) Nagasaki,\n");
+ printw("4) Saigon, 5) Manila, 6) Singapore, or\n");
+ printw("7) Batavia ? ");
+ refresh();
+
+ for (;;)
+ {
+ move(21, 13);
+ clrtobot();
+
+ choice = get_num(1);
+
+ if (choice == port)
+ {
+ printw("\n\nYou're already here, Taipan.");
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ } else if ((choice >= 1) && (choice <= 7)) {
+ port = choice;
+ break;
+ }
+ }
+
+ move(6, 43);
+ printw(" ");
+ attrset(A_REVERSE);
+ printw("%s", location[0]);
+ attrset(A_NORMAL);
+ printw(" ");
+
+ move(16, 0);
+ clrtobot();
+ printw(" Captain's Report\n\n");
+
+ if (rand()%bp == 0)
+ {
+ int num_ships = rand()%((capacity / 10) + guns) + 1;
+
+ if (num_ships > 9999)
+ {
+ num_ships = 9999;
+ }
+ printw("%d hostile ships approaching, Taipan!\n", num_ships);
+ refresh();
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ result = sea_battle(GENERIC, num_ships);
+ }
+
+ if (result == 2)
+ {
+ port_stats();
+ move(6, 43);
+ printw(" ");
+ attrset(A_REVERSE);
+ printw("%s", location[0]);
+ attrset(A_NORMAL);
+ printw(" ");
+
+ move(16, 0);
+ clrtobot();
+ printw(" Captain's Report\n\n");
+ printw("Li Yuen's fleet drove them off!");
+ refresh();
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+ }
+
+ if (((result == 0) && (rand()%(4 + (8 * li))) == 0) || (result == 2))
+ {
+ move(18, 0);
+ clrtobot();
+ printw("Li Yuen's pirates, Taipan!!\n\n");
+ refresh();
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ if (li > 0)
+ {
+ printw("Good joss!! They let us be!!\n");
+ refresh();
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ return;
+ } else {
+ int num_ships = rand()%((capacity / 5) + guns) + 5;
+
+ printw("%d ships of Li Yuen's pirate\n", num_ships);
+ printw("fleet, Taipan!!\n");
+ refresh();
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ sea_battle(LI_YUEN, num_ships);
+ }
+ }
+
+ if (result > 0)
+ {
+ port_stats();
+ move(6, 43);
+ printw(" ");
+ attrset(A_REVERSE);
+ printw("%s", location[0]);
+ attrset(A_NORMAL);
+ printw(" ");
+
+ move(16, 0);
+ clrtobot();
+ printw(" Captain's Report\n\n");
+ if (result == 1)
+ {
+ fancy_numbers(booty, fancy_num);
+ printw("We captured some booty.\n");
+ printw("It's worth %s!", fancy_num);
+ cash += booty;
+ } else if (result == 3) {
+ printw("We made it!");
+ } else {
+ printw("The buggers got us, Taipan!!!\n");
+ printw("It's all over, now!!!");
+ refresh();
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+
+ final_stats();
+ return;
+ }
+
+ refresh();
+ timeout(3000);
+ getch();
+ timeout(-1);
+ }
+
+ if (rand()%10 == 0)
+ {
+ move(18, 0);
+ clrtobot();
+ printw("Storm, Taipan!!\n\n");
+ refresh();
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ if (rand()%30 == 0)
+ {
+ printw(" I think we're going down!!\n\n");
+ refresh();
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ if (((damage / capacity * 3) * ((float) rand() / RAND_MAX)) >= 1)
+ {
+ printw("We're going down, Taipan!!\n");
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+
+ final_stats();
+ }
+ }
+
+ printw(" We made it!!\n\n");
+ refresh();
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ if (rand()%3 == 0)
+ {
+ int orig = port;
+
+ while (port == orig)
+ {
+ port = rand()%7 + 1;
+ }
+
+ move(18, 0);
+ clrtobot();
+ printw("We've been blown off course\n");
+ printw("to %s", location[port]);
+ refresh();
+ timeout(3000);
+ getch();
+ timeout(-1);
+ }
+ }
+
+ month++;
+ if (month == 13)
+ {
+ month = 1;
+ year++;
+ ec += 10;
+ ed += .5;
+ }
+
+ debt = debt + (debt * .1);
+ bank = bank + (bank * .005);
+ set_prices();
+
+ move(18, 0);
+ clrtobot();
+ printw("Arriving at %s...", location[port]);
+ refresh();
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ return;
+}
+
+void li_yuen_extortion(void)
+{
+ int time = ((year - 1860) * 12) + month,
+ choice = 0;
+
+ float i = 1.8,
+ j = 0,
+ amount = 0;
+
+ if (time > 12)
+ {
+ j = rand()%(1000 * time) + (1000 * time);
+ i = 1;
+ }
+
+ amount = ((cash / i) * ((float) rand() / RAND_MAX)) + j;
+
+ fancy_numbers(amount, fancy_num);
+
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Li Yuen asks %s in donation\n", fancy_num);
+ printw("to the temple of Tin Hau, the Sea\n");
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ move (20, 0);
+ clrtoeol();
+ printw("Goddess. Will you pay? ");
+ refresh();
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ if (amount <= cash)
+ {
+ cash -= amount;
+ li = 1;
+ } else {
+ move (18, 0);
+ clrtobot();
+ printw("Taipan, you do not have enough cash!!\n\n");
+ refresh();
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ printw("Do you want Elder Brother Wu to make up\n");
+ printw("the difference for you? ");
+ choice = 0;
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ amount -= cash;
+ debt += amount;
+ cash = 0;
+ li = 1;
+
+ move (18, 0);
+ clrtobot();
+ printw("Elder Brother has given Li Yuen the\n");
+ printw("difference between what he wanted and\n");
+ printw("your cash on hand and added the same\n");
+ printw("amount to your debt.\n");
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ } else {
+ cash = 0;
+
+ printw("Very well. Elder Brother Wu will not pay\n");
+ printw("Li Yuen the difference. I would be very\n");
+ printw("wary of pirates if I were you, Taipan.\n");
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ }
+
+ port_stats();
+
+ return;
+}
+
+void elder_brother_wu(void)
+{
+ int choice = 0;
+
+ long wu = 0;
+
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Do you have business with Elder Brother\n");
+ printw("Wu, the moneylender? ");
+
+ for (;;)
+ {
+ move (19, 21);
+ clrtoeol();
+ refresh();
+
+ choice = get_one();
+ if ((choice == 'N') || (choice == 'n'))
+ {
+ break;
+ } else if ((choice == 'Y') || (choice == 'y')) {
+ if (((int)cash == 0) && ((int)bank == 0) && (guns == 0) &&
+ (hold_[0] == 0) && (hkw_[0] == 0) &&
+ (hold_[1] == 0) && (hkw_[1] == 0) &&
+ (hold_[2] == 0) && (hkw_[2] == 0) &&
+ (hold_[3] == 0) && (hkw_[3] == 0))
+ {
+ int i = rand()%1500 + 500,
+ j;
+
+ wu_bailout++;
+ j = rand()%2000 * wu_bailout + 1500;
+
+ for (;;)
+ {
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Elder Brother is aware of your plight,\n");
+ printw("Taipan. He is willing to loan you an\n");
+ printw("additional %d if you will pay back\n", i);
+ printw("%d. Are you willing, Taipan? ", j);
+ refresh();
+
+ choice = get_one();
+ if ((choice == 'N') || (choice == 'n'))
+ {
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Very well, Taipan, the game is over!\n");
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+
+ final_stats();
+ } else if ((choice == 'Y') || (choice == 'y')) {
+ cash += i;
+ debt += j;
+ port_stats();
+
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Very well, Taipan. Good joss!!\n");
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+
+ return;
+ }
+ }
+ } else if ((cash > 0) && (debt != 0)) {
+ for (;;)
+ {
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("How much do you wish to repay\n");
+ printw("him? ");
+ refresh();
+
+ wu = get_num(9);
+ if (wu == -1)
+ {
+ wu = cash;
+ }
+ if (wu <= cash)
+ {
+ cash -= wu;
+ if ((wu > debt) && (debt > 0))
+ {
+ debt -= (wu + 1);
+ } else {
+ debt -= wu;
+ }
+ break;
+ } else {
+ move(18, 0);
+ clrtobot();
+ fancy_numbers(cash, fancy_num);
+ printw("Taipan, you only have %s\n", fancy_num);
+ printw("in cash.\n");
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ }
+ port_stats();
+
+ for (;;)
+ {
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("How much do you wish to\n");
+ printw("borrow? ");
+ refresh();
+
+ wu = get_num(9);
+ if (wu == -1)
+ {
+ wu = (cash * 2);
+ }
+ if (wu <= (cash * 2))
+ {
+ cash += wu;
+ debt += wu;
+ break;
+ } else {
+ printw("\n\nHe won't loan you so much, Taipan!");
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ port_stats();
+
+ break;
+ }
+ }
+
+ if ((debt > 20000) && (cash > 0) && (rand()%5 == 0))
+ {
+ int num = rand()%3 + 1;
+
+ cash = 0;
+ port_stats();
+
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Bad joss!!\n");
+ printw("%d of your bodyguards have been killed\n", num);
+ printw("by cutthroats and you have been robbed\n");
+ printw("of all of your cash, Taipan!!\n");
+
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+
+ return;
+}
+
+void good_prices(void)
+{
+ char item[14];
+
+ int i = rand()%4,
+ j = rand()%2;
+
+ if (i == 0)
+ {
+ strcpy(item, "Opium");
+ } else if (i == 1) {
+ strcpy(item, "Silk");
+ } else if (i == 2) {
+ strcpy(item, "Arms");
+ } else {
+ strcpy(item, "General Cargo");
+ }
+
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Taipan!! The price of %s\n", item);
+ if (j == 0)
+ {
+ price[i] = price[i] / 5;
+ printw("has dropped to %ld!!\n", price[i]);
+ } else {
+ price[i] = price[i] * (rand()%5 + 5);
+ printw("has risen to %ld!!\n", price[i]);
+ }
+
+ refresh();
+ timeout(3000);
+ getch();
+ timeout(-1);
+}
+
+void overload(void)
+{
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Your ship is overloaded, Taipan!!");
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+ return;
+}
+
+void new_ship(void)
+{
+ int choice = 0,
+ time;
+
+ float amount;
+
+ time = ((year - 1860) * 12) + month;
+ amount = rand()%(1000 * (time + 5) / 6) * (capacity / 50) + 1000;
+
+ if (cash < amount)
+ {
+ return;
+ }
+
+ fancy_numbers(amount, fancy_num);
+
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Do you wish to trade in your ");
+ if (damage > 0)
+ {
+ attrset(A_REVERSE);
+ printw("damaged");
+ attrset(A_NORMAL);
+ } else {
+ printw("fine");
+ }
+ printw("\nship for one with 50 more capacity by\n");
+ printw("paying an additional %s, Taipan? ", fancy_num);
+ refresh();
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ cash -= amount;
+ hold += 50;
+ capacity += 50;
+ damage = 0;
+ }
+
+ if ((rand()%2 == 0) && (guns < 1000))
+ {
+ port_stats();
+ new_gun();
+ }
+
+ port_stats();
+
+ return;
+}
+
+void new_gun(void)
+{
+ int choice = 0,
+ time;
+
+ float amount;
+
+ time = ((year - 1860) * 12) + month;
+ amount = rand()%(1000 * (time + 5) / 6) + 500;
+
+ if ((cash < amount) || (hold < 10))
+ {
+ return;
+ }
+
+ fancy_numbers(amount, fancy_num);
+
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Do you wish to buy a ship's gun\n");
+ printw("for %s, Taipan? ", fancy_num);
+ refresh();
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ cash -= amount;
+ hold -= 10;
+ guns += 1;
+ }
+
+ port_stats();
+
+ return;
+}
+
+void fancy_numbers(float num, char *fancy)
+{
+ char number[18];
+
+ if (num >= 100000000)
+ {
+ int num1 = (num / 1000000);
+ sprintf(number, "%d", num1);
+ strcpy(fancy, number);
+ strcat(fancy, " Million");
+ } else if (num >= 10000000) {
+ int num1 = (num / 1000000);
+ int num2 = (((int) num % 1000000) / 100000);
+ sprintf(number, "%d", num1);
+ strcpy(fancy, number);
+ if (num2 > 0)
+ {
+ strcat(fancy, ".");
+ sprintf(number, "%d", num2);
+ strcat(fancy, number);
+ }
+ strcat(fancy, " Million");
+ } else if (num >= 1000000) {
+ int num1 = (num / 1000000);
+ int num2 = (((int) num % 1000000) / 10000);
+ sprintf(number, "%d", num1);
+ strcpy(fancy, number);
+ if (num2 > 0)
+ {
+ strcat(fancy, ".");
+ sprintf(number, "%d", num2);
+ strcat(fancy, number);
+ }
+ strcat(fancy, " Million");
+ } else {
+ sprintf(number, "%d", (int) num);
+ strcpy(fancy, number);
+ }
+}
+
+int sea_battle(int id, int num_ships)
+{
+ int orders = 0,
+ num_on_screen = 0,
+ ships_on_screen[10],
+ time = ((year - 1860) * 12) + month,
+ s0 = num_ships,
+ ok = 0,
+ ik = 1,
+ x, y, i,
+ input,
+ status;
+
+ booty = (time / 4 * 1000 * num_ships) + rand()%1000 + 250;
+
+ for (i = 0; i <= 9; i++)
+ {
+ ships_on_screen[i] = 0;
+ }
+
+ clear();
+ flushinp();
+ fight_stats(num_ships, orders);
+
+ while (num_ships > 0)
+ {
+ status = 100 - (((float) damage / capacity) * 100);
+ if (status <= 0)
+ {
+ return 4;
+ }
+ flushinp();
+ move(3, 0);
+ clrtoeol();
+ printw("Current seaworthiness: %s (%d%%)", st[(status / 20)], status);
+ refresh();
+
+ x = 10;
+ y = 6;
+ for (i = 0; i <= 9; i++)
+ {
+ if (i == 5)
+ {
+ x = 10;
+ y = 12;
+ }
+
+ if (num_ships > num_on_screen)
+ {
+ if (ships_on_screen[i] == 0)
+ {
+ usleep(100000);
+ ships_on_screen[i] =
+ (int)((ec * ((float) rand() / RAND_MAX)) + 20);
+ draw_lorcha(x, y);
+ num_on_screen++;
+ refresh();
+ }
+
+ x += 10;
+ }
+ }
+
+ if (num_ships > num_on_screen)
+ {
+ move(11, 62);
+ printw("+");
+ } else {
+ move(11, 62);
+ printw(" ");
+ }
+
+ move(16, 0);
+ printw("\n");
+ refresh();
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+
+ if ((input == 'F') || (input == 'f'))
+ {
+ orders = 1;
+ } else if ((input == 'R') || (input == 'r')) {
+ orders = 2;
+ } else if ((input == 'T') || (input == 't')) {
+ orders = 3;
+ }
+
+ if (orders == 0)
+ {
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+
+ if ((input == 'F') || (input == 'f'))
+ {
+ orders = 1;
+ } else if ((input == 'R') || (input == 'r')) {
+ orders = 2;
+ } else if ((input == 'T') || (input == 't')) {
+ orders = 3;
+ } else {
+ move(3, 0);
+ clrtoeol();
+ printw("Taipan, what shall we do?? (f=fight, r=run, t=throw cargo)");
+ refresh();
+ timeout(-1);
+ while ((input != 'F') && (input != 'f') &&
+ (input != 'R') && (input != 'r') &&
+ (input != 'T') && (input != 't'))
+ {
+ input = getch();
+ }
+ if ((input == 'F') || (input == 'f'))
+ {
+ orders = 1;
+ } else if ((input == 'R') || (input == 'r')) {
+ orders = 2;
+ } else {
+ orders = 3;
+ }
+ }
+ }
+
+ fight_stats(num_ships, orders);
+ if ((orders == 1) && (guns > 0))
+ {
+ int targeted,
+ sk = 0;
+
+ ok = 3;
+ ik = 1;
+ move(3, 0);
+ clrtoeol();
+ printw("Aye, we'll fight 'em, Taipan.");
+ refresh();
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+
+ move(3, 0);
+ clrtoeol();
+ printw("We're firing on 'em, Taipan!");
+ timeout(1000);
+ input = getch();
+ timeout(-1);
+ refresh();
+
+ 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))
+ {
+ int j;
+
+ x = 10;
+ y = 6;
+ for (j = 0; j <= 9; j++)
+ {
+ if (j == 5)
+ {
+ x = 10;
+ y = 12;
+ }
+
+ if (num_ships > num_on_screen)
+ {
+ if (ships_on_screen[j] == 0)
+ {
+ usleep(100000);
+ ships_on_screen[j] =
+ (int)((ec * ((float) rand() / RAND_MAX)) + 20);
+ draw_lorcha(x, y);
+ num_on_screen++;
+ }
+
+ x += 10;
+ }
+ }
+ }
+
+ move(11, 62);
+ if (num_ships > num_on_screen)
+ {
+ printw("+");
+ } else {
+ printw(" ");
+ }
+
+ move(16, 0);
+ printw("\n");
+ refresh();
+
+ targeted = rand()%10;
+ while (ships_on_screen[targeted] == 0)
+ {
+ targeted = rand()%10;
+ }
+
+ x = (targeted < 5) ? ((targeted + 1) * 10) : ((targeted - 4) * 10);
+ y = (targeted < 5) ? 6 : 12;
+
+ draw_blast(x, y);
+ refresh();
+ usleep(100000);
+
+ draw_lorcha(x, y);
+ refresh();
+ usleep(100000);
+
+ draw_blast(x, y);
+ refresh();
+ usleep(100000);
+
+ draw_lorcha(x, y);
+ refresh();
+ usleep(100000);
+
+ ships_on_screen[targeted] -= rand()%30 + 10;
+
+ if (ships_on_screen[targeted] <= 0)
+ {
+ num_on_screen--;
+ num_ships--;
+ sk++;
+ ships_on_screen[targeted] = 0;
+
+ usleep(100000);
+
+ sink_lorcha(x, y);
+
+ if (num_ships == num_on_screen)
+ {
+ move(11, 62);
+ printw(" ");
+ }
+
+ fight_stats(num_ships, orders);
+ refresh();
+ }
+
+ if (num_ships == 0)
+ {
+ i += guns;
+ } else {
+ usleep(500000);
+ }
+ }
+ move(3, 0);
+ clrtoeol();
+ if (sk > 0)
+ {
+ printw("Sunk %d of the buggers, Taipan!", sk);
+ } else {
+ printw("Hit 'em, but didn't sink 'em, Taipan!");
+ }
+ refresh();
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+
+ if ((rand()%s0 > (num_ships * .6 / id)) && (num_ships > 2))
+ {
+ int ran = rand()%(num_ships / 3 / id) + 1;
+
+ num_ships -= ran;
+ fight_stats(num_ships, orders);
+ move(3, 0);
+ clrtoeol();
+ printw("%d ran away, Taipan!", ran);
+
+ if (num_ships <= 10)
+ {
+ for (i = 9; i >= 0; i--)
+ {
+ if ((num_on_screen > num_ships) && (ships_on_screen[i] > 0))
+ {
+ ships_on_screen[i] = 0;
+ num_on_screen--;
+
+ x = (i < 5) ? ((i + 1) * 10) : ((i - 4) * 10);
+ y = (i < 5) ? 6 : 12;
+ clear_lorcha(x, y);
+ refresh();
+ usleep(100000);
+ }
+ }
+ if (num_ships == num_on_screen)
+ {
+ move(11, 62);
+ printw(" ");
+ refresh();
+ }
+
+ }
+
+ move(16, 0);
+
+ refresh();
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+
+ if ((input == 'F') || (input == 'f'))
+ {
+ orders = 1;
+ } else if ((input == 'R') || (input == 'r')) {
+ orders = 2;
+ } else if ((input == 'T') || (input == 't')) {
+ orders = 3;
+ }
+ }
+ } else if ((orders == 1) && (guns == 0)) {
+ move(3, 0);
+ clrtoeol();
+ printw("We have no guns, Taipan!!");
+ refresh();
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ } else if (orders == 3) {
+ int choice = 0;
+
+ long amount = 0,
+ total = 0;
+
+ move(18, 0);
+ printw("You have the following on board, Taipan:");
+ move(19, 4);
+ printw("Opium: %d", hold_[0]);
+ move(19, 24);
+ printw("Silk: %d", hold_[1]);
+ move(20, 5);
+ printw("Arms: %d", hold_[2]);
+ move(20, 21);
+ printw("General: %d", hold_[3]);
+
+ move(3, 0);
+ clrtoeol();
+ printw("What shall I throw overboard, Taipan? ");
+ refresh();
+
+ while ((choice != 'O') && (choice != 'o') &&
+ (choice != 'S') && (choice != 's') &&
+ (choice != 'A') && (choice != 'a') &&
+ (choice != 'G') && (choice != 'g') &&
+ (choice != '*'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'O') || (choice == 'o'))
+ {
+ choice = 0;
+ } else if ((choice == 'S') || (choice == 's')) {
+ choice = 1;
+ } else if ((choice == 'A') || (choice == 'a')) {
+ choice = 2;
+ } else if ((choice == 'G') || (choice == 'g')) {
+ choice = 3;
+ } else {
+ choice = 4;
+ }
+
+ if (choice < 4)
+ {
+ move(3, 0);
+ clrtoeol();
+ printw("How much, Taipan? ");
+ refresh();
+
+ amount = get_num(9);
+ if ((hold_[choice] > 0) && ((amount == -1) || (amount > hold_[choice])))
+ {
+ amount = hold_[choice];
+ }
+ total = hold_[choice];
+ } else {
+ total = hold_[0] + hold_[1] + hold_[2] + hold_[3];
+ }
+
+ if (total > 0)
+ {
+ move(3, 0);
+ clrtoeol();
+ printw("Let's hope we lose 'em, Taipan!");
+ if (choice < 4)
+ {
+ hold_[choice] -= amount;
+ hold += amount;
+ ok += (amount / 10);
+ } else {
+ hold_[0] = 0;
+ hold_[1] = 0;
+ hold_[2] = 0;
+ hold_[3] = 0;
+ hold += total;
+ ok += (total / 10);
+ }
+ move(18, 0);
+ clrtobot();
+ refresh();
+
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ } else {
+ move(3, 0);
+ clrtoeol();
+ printw("There's nothing there, Taipan!");
+ move(18, 0);
+ clrtobot();
+ refresh();
+
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ }
+ }
+
+ if ((orders == 2) || (orders == 3))
+ {
+ if (orders == 2)
+ {
+ move(3, 0);
+ clrtoeol();
+ printw("Aye, we'll run, Taipan.");
+ refresh();
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ }
+
+ ok += ik++;
+ if (rand()%ok > rand()%num_ships)
+ {
+ flushinp();
+ move(3, 0);
+ clrtoeol();
+ printw("We got away from 'em, Taipan!");
+ refresh();
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ num_ships = 0;
+ } else {
+ move(3, 0);
+ clrtoeol();
+ printw("Couldn't lose 'em.");
+ refresh();
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+
+ if ((num_ships > 2) && (rand()%5 == 0))
+ {
+ int lost = (rand()%num_ships / 2) + 1;
+
+ num_ships -= lost;
+ fight_stats(num_ships, orders);
+ move(3, 0);
+ clrtoeol();
+ printw("But we escaped from %d of 'em!", lost);
+
+ if (num_ships <= 10)
+ {
+ for (i = 9; i >= 0; i--)
+ {
+ if ((num_on_screen > num_ships) && (ships_on_screen[i] > 0))
+ {
+ ships_on_screen[i] = 0;
+ num_on_screen--;
+
+ x = (i < 5) ? ((i + 1) * 10) : ((i - 4) * 10);
+ y = (i < 5) ? 6 : 12;
+ clear_lorcha(x, y);
+ refresh();
+ usleep(100000);
+ }
+ }
+ if (num_ships == num_on_screen)
+ {
+ move(11, 62);
+ printw(" ");
+ refresh();
+ }
+ }
+
+ move(16, 0);
+
+ refresh();
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+
+ if ((input == 'F') || (input == 'f'))
+ {
+ orders = 1;
+ } else if ((input == 'R') || (input == 'r')) {
+ orders = 2;
+ } else if ((input == 'T') || (input == 't')) {
+ orders = 3;
+ }
+ }
+ }
+ }
+
+ if (num_ships > 0)
+ {
+ move(3, 0);
+ clrtoeol();
+ printw("They're firing on us, Taipan!");
+
+ refresh();
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ flushinp();
+ for (i = 0; i < 3; i++)
+ {
+ for (y = 0; y < 24; y++)
+ {
+ for (x = 0; x < 79; x++)
+ {
+ move(y, x);
+ printw("*");
+ }
+ }
+ refresh();
+ usleep(200000);
+ clear();
+ refresh();
+ usleep(200000);
+ }
+
+ fight_stats(num_ships, orders);
+ x = 10;
+ y = 6;
+ for (i = 0; i <= 9; i++)
+ {
+ if (i == 5)
+ {
+ x = 10;
+ y = 12;
+ }
+
+ if (ships_on_screen[i] > 0)
+ {
+ draw_lorcha(x, y);
+ }
+
+ x += 10;
+ }
+
+ move(11, 62);
+ if (num_ships > num_on_screen)
+ {
+ printw("+");
+ } else {
+ printw(" ");
+ }
+
+ move(3, 0);
+ clrtoeol();
+ printw("We've been hit, Taipan!!");
+
+ refresh();
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+
+ i = (num_ships > 15) ? 15 : num_ships;
+ if ((guns > 0) && ((rand()%100 < (((float) damage / capacity) * 100)) ||
+ ((((float) damage / capacity) * 100) > 80)))
+ {
+ i = 1;
+ guns--;
+ hold += 10;
+ fight_stats(num_ships, orders);
+ move(3, 0);
+ clrtoeol();
+ printw("The buggers hit a gun, Taipan!!");
+ fight_stats(num_ships, orders);
+
+ refresh();
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ }
+ damage = damage + ((ed * i * id) * ((float) rand() / RAND_MAX)) + (i / 2);
+ if ((id == GENERIC) && (rand()%20 == 0))
+ {
+ return 2;
+ }
+ }
+ }
+
+ if (orders == 1)
+ {
+ clear();
+ fight_stats(num_ships, orders);
+ move(3, 0);
+ clrtoeol();
+ printw("We got 'em all, Taipan!");
+ refresh();
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ return 1;
+ } else {
+ return 3;
+ }
+}
+
+void draw_lorcha(int x, int y)
+{
+ move (y, x);
+ printw("-|-_|_ ");
+ move ((y + 1), x);
+ printw("-|-_|_ ");
+ move ((y + 2), x);
+ printw("_|__|__/");
+ move ((y + 3), x);
+ printw("\\_____/ ");
+}
+
+void clear_lorcha(int x, int y)
+{
+ move (y, x);
+ printw(" ");
+ move ((y + 1), x);
+ printw(" ");
+ move ((y + 2), x);
+ printw(" ");
+ move ((y + 3), x);
+ printw(" ");
+}
+
+void draw_blast(int x, int y)
+{
+ move (y, x);
+ printw("********");
+ move ((y + 1), x);
+ printw("********");
+ move ((y + 2), x);
+ printw("********");
+ move ((y + 3), x);
+ printw("********");
+}
+
+void sink_lorcha(int x, int y)
+{
+ int delay = rand()%20;
+
+ move (y, x);
+ printw(" ");
+ move ((y + 1), x);
+ printw("-|-_|_ ");
+ move ((y + 2), x);
+ printw("-|-_|_ ");
+ move ((y + 3), x);
+ printw("_|__|__/");
+ refresh();
+ usleep(500000);
+ if (delay == 0)
+ {
+ usleep(500000);
+ }
+
+ move ((y + 1), x);
+ printw(" ");
+ move ((y + 2), x);
+ printw("-|-_|_ ");
+ move ((y + 3), x);
+ printw("-|-_|_ ");
+ refresh();
+ usleep(500000);
+ if (delay == 0)
+ {
+ usleep(500000);
+ }
+
+ move ((y + 2), x);
+ printw(" ");
+ move ((y + 3), x);
+ printw("-|-_|_ ");
+ refresh();
+ usleep(500000);
+ if (delay == 0)
+ {
+ usleep(500000);
+ }
+
+ move ((y + 3), x);
+ printw(" ");
+ refresh();
+ usleep(500000);
+ if (delay == 0)
+ {
+ usleep(500000);
+ }
+}
+
+void fight_stats(int ships, int orders)
+{
+ char ch_orders[12];
+
+ if (orders == 0)
+ {
+ strcpy(ch_orders, "\0");
+ } else if (orders == 1) {
+ strcpy(ch_orders, "Fight ");
+ } else if (orders == 2) {
+ strcpy(ch_orders, "Run ");
+ } else {
+ strcpy(ch_orders, "Throw Cargo");
+ }
+
+ move(0, 0);
+ if (ships >= 1000)
+ {
+ printw("%d", ships);
+ } else if (ships >= 100) {
+ printw(" %d", ships);
+ } else if (ships >= 10) {
+ printw(" %d", ships);
+ } else {
+ printw(" %d", ships);
+ }
+ move(0, 5);
+ if (ships == 1)
+ {
+ printw("ship attacking, Taipan! \n");
+ } else {
+ printw("ships attacking, Taipan!\n");
+ }
+ printw("Your orders are to: %s", ch_orders);
+ move(0, 50);
+ printw("| We have");
+ move(1, 50);
+ printw("| %d guns", guns);
+ move(2, 50);
+ printw("----------");
+ move(16, 0);
+
+ return;
+}
+
+void mchenry(void)
+{
+ int choice = 0;
+
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ printw("Taipan, Mc Henry from the Hong Kong\n");
+ printw("Shipyards has arrived!! He says, \"I see\n");
+ printw("ye've a wee bit of damage to yer ship.\n");
+ printw("Will ye be wanting repairs? ");
+ refresh();
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ int percent = ((float) damage / capacity) * 100,
+ time = ((year - 1860) * 12) + month;
+
+ long br = ((((60 * (time + 3) / 4) * (float) rand() / RAND_MAX) +
+ 25 * (time + 3) / 4) * capacity / 50),
+ repair_price = (br * damage) + 1,
+ amount;
+
+ move(18, 0);
+ clrtobot();
+ printw("Och, 'tis a pity to be %d%% damaged.\n", percent);
+ printw("We can fix yer whole ship for %ld,\n", repair_price);
+ printw("or make partial repairs if you wish.\n");
+ printw("How much will ye spend? ");
+ refresh();
+
+ for (;;)
+ {
+ move(21, 24);
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = cash;
+ }
+ if (amount <= cash)
+ {
+ cash -= amount;
+ damage -= (int)((amount / br) + .5);
+ damage = (damage < 0) ? 0 : damage;
+ port_stats();
+ refresh();
+ break;
+ }
+ }
+ }
+
+ return;
+}
+
+void retire(void)
+{
+ move(16, 0);
+ clrtobot();
+ printw("Comprador's Report\n\n");
+ attrset(A_REVERSE);
+ printw(" \n");
+ printw(" Y o u ' r e a \n");
+ printw(" \n");
+ printw(" M I L L I O N A I R E ! \n");
+ printw(" \n");
+ attrset(A_NORMAL);
+ refresh();
+ timeout(5000);
+ getch();
+ timeout(-1);
+
+ final_stats();
+}
+
+void final_stats(void)
+{
+ int years = year - 1860,
+ time = ((year - 1860) * 12) + month,
+ choice = 0;
+
+ clear();
+ printw("Your final status:\n\n");
+ cash = cash + bank - debt;
+ fancy_numbers(cash, fancy_num);
+ printw("Net cash: %s\n\n", fancy_num);
+ printw("Ship size: %d units with %d guns\n\n", capacity, guns);
+ printw("You traded for %d year", years);
+ if (years != 1)
+ {
+ printw("s");
+ }
+ printw(" and %d month", month);
+ if (month > 1)
+ {
+ printw("s");
+ }
+ printw("\n\n");
+ cash = cash / 100 / time;
+ attrset(A_REVERSE);
+ printw("Your score is %.0f.\n", cash);
+ attrset(A_NORMAL);
+ printw("\n");
+ if ((cash < 100) && (cash >= 0))
+ {
+ printw("Have you considered a land based job?\n\n\n");
+ } else if (cash < 0) {
+ printw("The crew has requested that you stay on\n");
+ printw("shore for their safety!!\n\n");
+ } else {
+ printw("\n\n\n");
+ }
+ printw("Your Rating:\n");
+ printw(" _______________________________\n");
+ printw("|");
+ if (cash > 49999)
+ {
+ attrset(A_REVERSE);
+ }
+ printw("Ma Tsu");
+ attrset(A_NORMAL);
+ printw(" 50,000 and over |\n");
+ printw("|");
+ if ((cash < 50000) && (cash > 7999))
+ {
+ attrset(A_REVERSE);
+ }
+ printw("Master Taipan");
+ attrset(A_NORMAL);
+ printw(" 8,000 to 49,999|\n");
+ printw("|");
+ if ((cash < 8000) && (cash > 999))
+ {
+ attrset(A_REVERSE);
+ }
+ printw("Taipan");
+ attrset(A_NORMAL);
+ printw(" 1,000 to 7,999|\n");
+ printw("|");
+ if ((cash < 1000) && (cash > 499))
+ {
+ attrset(A_REVERSE);
+ }
+ printw("Compradore");
+ attrset(A_NORMAL);
+ printw(" 500 to 999|\n");
+ printw("|");
+ if (cash < 500)
+ {
+ attrset(A_REVERSE);
+ }
+ printw("Galley Hand");
+ attrset(A_NORMAL);
+ printw(" less than 500|\n");
+ printw("|_______________________________|\n\n");
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ move (22, 0);
+ clrtoeol();
+ printw("Play again? ");
+ refresh();
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ bank = 0;
+ hkw_[0] = 0;
+ hkw_[1] = 0;
+ hkw_[3] = 0;
+ hkw_[4] = 0;
+ hold_[0] = 0;
+ hold_[1] = 0;
+ hold_[2] = 0;
+ hold_[3] = 0;
+ hold = 0;
+ capacity = 60;
+ damage = 0;
+ month = 1;
+ year = 1860;
+ port = 1;
+
+ splash_intro();
+ name_firm();
+ cash_or_guns();
+ set_prices();
+
+ return;
+ }
+
+ clear();
+ refresh();
+ nocbreak();
+ endwin();
+
+ exit(0);
+}
diff --git a/taipan.c b/taipan.c
new file mode 100644
index 0000000..b53ac1c
--- /dev/null
+++ b/taipan.c
@@ -0,0 +1,2706 @@
+#include <conio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <peekpoke.h>
+
+/* 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
+
+/**** atari-specific stuff */
+
+void atari_text_setup() {
+ POKE(710, 0xc0); // green background
+ POKE(709, 0x0c); // bright text
+ POKE(756, 0xb8); // use our custom font
+}
+
+/* values returned by cgetc() for backspace & enter keys */
+#define BKSP 0x7e
+#define ENTER 0x9b
+
+/* timed_getch() args for seconds, based on jiffy clock of
+ target system. No adjustment made for PAL, sorry. */
+#define TMOUT_1S 60
+#define TMOUT_3S 180
+#define TMOUT_5S 300
+#define TMOUT_5M 18000
+
+/* wait up to j jiffies for a keypress. returns -1 if no key pressed */
+extern int __fastcall__ timed_getch(unsigned int j);
+
+/* sleep for j jiffies (no PAL adjustment at the moment) */
+extern void __fastcall__ jsleep(unsigned int j);
+
+#define flushinp() (POKE(764,255))
+
+/* Atari-specific random number functions from rand.s.
+ Non-Atari platforms can probably just:
+#define initrand() _randomize();
+#define randi() rand();
+#define randl() (unsigned long)((randi() << 16) | randi())
+*/
+
+#define initrand() /* no-op on Atari */
+extern unsigned int __fastcall__ randi(void);
+extern unsigned long __fastcall__ randl(void);
+
+/* used to use this:
+unsigned long randl() {
+ unsigned long r = rand();
+ char *buf = (char *)r;
+ buf[2] = PEEK(53770);
+ buf[3] = PEEK(53770);
+ return r;
+}
+*/
+
+
+/**** End of atari-specific stuff */
+
+unsigned long randclamp(unsigned long clamp) {
+ return randl() % clamp;
+}
+
+/* TODO: rewrite in asm */
+void clrtobot() {
+ unsigned char rows, cols, y, oldx, oldy;
+ oldx = wherex();
+ oldy = wherey();
+ screensize(&cols, &rows);
+ cclear(cols - wherex()); /* leaves cursor at start of next line */
+ for(y = wherey(); y < rows; y++)
+ cclearxy(0, y, cols);
+ gotoxy(oldx, oldy);
+}
+
+/* TODO: rewrite in asm */
+void clrtoeol() {
+ unsigned char cols, rows, oldx, oldy;
+ oldx = wherex();
+ oldy = wherey();
+ screensize(&cols, &rows);
+ cclear(cols - wherex());
+ gotoxy(oldx, oldy);
+}
+
+/* TODO: rewrite in asm */
+int lc(int a) {
+ if(a >= 'A' && a <= 'Z') a ^= 0x20;
+ return a;
+}
+
+/* TODO: rewrite in asm */
+/* wrapper for cgetc() that returns letters as lowercase only
+ (and everything else normally). Avoids a bunch of reduntant
+ if(foo == 'A' || foo == 'a') tests. */
+int lcgetch() {
+ return lc(cgetc());
+}
+
+/* taipan functions (modified as little as possible) */
+#define GENERIC 1
+#define LI_YUEN 2
+
+void splash_intro(void);
+int get_one(void);
+unsigned long get_num(int maxlen);
+void name_firm(void);
+void cash_or_guns(void);
+void set_prices(void);
+void port_stats(void);
+int port_choices(void);
+void new_ship(void);
+void new_gun(void);
+void li_yuen_extortion(void);
+void elder_brother_wu(void);
+void good_prices(void);
+void buy(void);
+void sell(void);
+void visit_bank(void);
+void transfer(void);
+void quit(void);
+void overload(void);
+void fancy_numbers(unsigned long num, char *fancy);
+int sea_battle(int id, int num_ships);
+extern void __fastcall__ draw_lorcha(int which, int displacement, int mask);
+void clear_lorcha(int x, int y);
+void draw_blast(int x, int y);
+void sink_lorcha(int which);
+void fight_stats(int ships, int orders);
+void mchenry(void);
+void retire(void);
+void final_stats(void);
+
+char firm[23],
+ fancy_num[24];
+
+char *item[] = { "Opium", "Silk", "Arms", "General Cargo" };
+
+char *location[] = { "At sea", "Hong Kong", "Shanghai", "Nagasaki",
+ "Saigon", "Manila", "Singapore", "Batavia" };
+
+char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+char *st[] = { "Critical", " Poor", " Fair",
+ " Good", " Prime", "Perfect" };
+
+unsigned long cash = 0,
+ bank = 0,
+ debt = 0,
+ booty = 0,
+ ec = 20,
+ ed = 1; // used to be a float, 0.5
+
+unsigned long price[4];
+
+int base_price[4][8] = { {1000, 11, 16, 15, 14, 12, 10, 13},
+ {100, 11, 14, 15, 16, 10, 13, 12},
+ {10, 12, 16, 10, 11, 13, 14, 15},
+ {1, 10, 11, 12, 13, 14, 15, 16} };
+
+int hkw_[4],
+ hold_[4];
+
+int hold = 0,
+ capacity = 60,
+ guns = 0,
+ bp = 0,
+ damage = 0,
+ month = 1,
+ year = 1860,
+ li = 0,
+ port = 1,
+ wu_warn = 0,
+ wu_bailout = 0;
+
+/* print an int or long as a string, conio-style */
+void cprintulong(unsigned long ul) {
+ cputs(ultoa(ul, fancy_num, 10));
+}
+
+#ifdef COMBAT_TEST
+void show_damage(void) {
+ cputc(' ');
+ cprintulong(damage);
+ cputc('/');
+ cprintulong(capacity);
+}
+#else
+#define show_damage()
+#endif
+
+// fancy_numbers() will get replaced sooner or later.
+// void cprintfancy(unsigned long ul) {
+// }
+
+void at_sea() {
+ gotoxy(30, 6);
+ cputc(' ');
+ revers(1);
+ cputs(location[0]);
+ revers(0);
+ cputc(' ');
+ cputc(' ');
+}
+
+/* this bit of code was duplicated a *bunch* of times,
+ making it a function makes the binary 2K smaller. */
+
+void prepare_report() {
+ gotoxy(0, 16);
+ clrtobot();
+}
+
+void compradores_report() {
+ prepare_report();
+ cputs("Comprador's Report\r\n\n");
+}
+
+void captains_report() {
+ prepare_report();
+ cputs(" Captain's Report\r\n\n");
+}
+
+
+void overload(void)
+{
+ compradores_report();
+ cputs("Your ship is overloaded, Taipan!!");
+ timed_getch(TMOUT_5S);
+ return;
+}
+
+void new_ship(void)
+{
+ int choice = 0,
+ time;
+
+ // float amount;
+ unsigned long amount;
+
+ time = ((year - 1860) * 12) + month;
+ amount = randi()%(1000 * (time + 5) / 6) * (capacity / 50) + 1000;
+
+ if (cash < amount)
+ {
+ return;
+ }
+
+ fancy_numbers(amount, fancy_num);
+
+ compradores_report();
+ cputs("Do you wish to trade in your ");
+ if (damage > 0)
+ {
+ revers(1);
+ cputs("damaged");
+ revers(0);
+ } else {
+ cputs("fine");
+ }
+ cputs("\r\nship for one with 50 more capacity by\r\n");
+ cputs("paying an additional ");
+ cputs(fancy_num);
+ cputs(", Taipan? ");
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ cash -= amount;
+ hold += 50;
+ capacity += 50;
+ damage = 0;
+ }
+
+ if ((randi()%2 == 0) && (guns < 1000))
+ {
+ port_stats();
+ new_gun();
+ }
+
+ port_stats();
+
+ return;
+}
+
+void new_gun(void)
+{
+ int choice = 0,
+ time;
+
+ unsigned long amount;
+
+ time = ((year - 1860) * 12) + month;
+ amount = randi()%(1000 * (time + 5) / 6) + 500;
+
+ if ((cash < amount) || (hold < 10))
+ {
+ return;
+ }
+
+ fancy_numbers(amount, fancy_num);
+
+ compradores_report();
+ cputs("Do you wish to buy a ship's gun\r\n for ");
+ cputs(fancy_num);
+ cputs(", Taipan? ");
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ cash -= amount;
+ hold -= 10;
+ guns += 1;
+ }
+
+ port_stats();
+
+ return;
+}
+
+void fancy_numbers(unsigned long num, char *fancy)
+{
+ /* note to self: find out why there's graphic corruption
+ if this isn't static. It's caused by sprintf() or strcpy()
+ writing to the font, which is supposed to be above cc65's max
+ usable address! */
+ static char number[18];
+ char mil = 0;
+ unsigned int num1, num2;
+
+ if (num >= 100000000L)
+ {
+ num1 = (num / 1000000L);
+ ultoa(num1, fancy, 10);
+ mil = 1;
+ } else if (num >= 10000000L) {
+ num1 = (num / 1000000L);
+ num2 = ((num % 1000000L) / 100000L);
+ ultoa(num1, fancy, 10);
+ if (num2 > 0)
+ {
+ strcat(fancy, ".");
+ ultoa(num2, number, 10);
+ strcat(fancy, number);
+ }
+ mil = 1;
+ } else if (num >= 1000000L) {
+ num1 = (num / 1000000L);
+ num2 = ((num % 1000000L) / 10000L);
+ ultoa(num1, fancy, 10);
+ if (num2 > 0)
+ {
+ strcat(fancy, ".");
+ ultoa(num2, number, 10);
+ strcat(fancy, number);
+ }
+ mil = 1;
+ } else {
+ ultoa(num, fancy, 10);
+ }
+
+ if(mil) strcat(fancy, " Million");
+}
+
+/*
+void fancytest(void) {
+ fancy_numbers(1000, fancy_num);
+ cputs(fancy_num);
+ cputs("\r\n");
+ fancy_numbers(10000, fancy_num);
+ cputs(fancy_num);
+ cputs("\r\n");
+ fancy_numbers(100000, fancy_num);
+ cputs(fancy_num);
+ cputs("\r\n");
+ fancy_numbers(1000000, fancy_num);
+ cputs(fancy_num);
+ cputs("\r\n");
+ fancy_numbers(4294967295, fancy_num); // LONG_MAX
+ cputs(fancy_num);
+ cputs("\r\n");
+ cgetc();
+}
+*/
+
+void fight_stats(int ships, int orders)
+{
+ // char ch_orders[12];
+
+ /*
+ if (orders == 0)
+ {
+ strcpy(ch_orders, "\0");
+ } else if (orders == 1) {
+ strcpy(ch_orders, "Fight ");
+ } else if (orders == 2) {
+ strcpy(ch_orders, "Run ");
+ } else {
+ strcpy(ch_orders, "Throw Cargo");
+ }
+ */
+
+ gotoxy(0, 0);
+
+ /*
+ if (ships >= 1000)
+ {
+ printw("%d", ships);
+ } else if (ships >= 100) {
+ printw(" %d", ships);
+ } else if (ships >= 10) {
+ printw(" %d", ships);
+ } else {
+ printw(" %d", ships);
+ }
+ */
+
+ if(ships < 1000) cputc(' ');
+ if(ships < 100) cputc(' ');
+ if(ships < 10) cputc(' ');
+ cprintulong(ships);
+
+ // gotoxy(0, 5);
+ cputs(" ship");
+ if(ships != 1) cputc('s');
+ cputs(" attacking, Taipan! \r\n");
+
+ /*
+ if (ships == 1)
+ {
+ printw("ship attacking, Taipan! \n");
+ } else {
+ printw("ships attacking, Taipan!\n");
+ }
+ */
+
+ // printw("Your orders are to: %s", ch_orders);
+ cputs("Your orders are to: ");
+ if(orders == 1)
+ cputs("Fight ");
+ else if(orders == 2)
+ cputs("Run ");
+ else if(orders == 3)
+ cputs("Throw Cargo");
+
+ /*
+ move(0, 50);
+ printw("| We have");
+ move(1, 50);
+ printw("| %d guns", guns);
+ move(2, 50);
+ printw("----------");
+ move(16, 0);
+ */
+
+ revers(1);
+ gotoxy(30, 0);
+ cputs(" We have");
+ gotoxy(30, 1);
+ cputc(' ');
+ if(guns < 1000) cputc(' ');
+ if(guns < 100) cputc(' ');
+ if(guns < 10) cputc(' ');
+ cprintulong(guns);
+ cputs(" guns");
+ revers(0);
+ return;
+}
+
+void sink_lorcha(int which) {
+ int i;
+ for(i = 1; i < 8; i++) {
+ draw_lorcha(which, i, 0);
+ jsleep(5);
+ }
+}
+
+/* print an inverse video plus if there are offscreen ships,
+ or clear it to a space if not. */
+void plus_or_space(unsigned char b) {
+ gotoxy(39, 15);
+ cputc(b ? 0xab : ' ');
+}
+
+int sea_battle(int 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 orders,
+ num_on_screen,
+ time,
+ s0,
+ ok,
+ ik,
+ i,
+ input,
+ status;
+
+ orders = 0;
+ num_on_screen = 0;
+ time = ((year - 1860) * 12) + month;
+ s0 = num_ships;
+ ok = 0;
+ ik = 1;
+
+ booty = (time / 4 * 1000 * num_ships) + randi()%1000 + 250;
+
+ for(i = 0; i <= 9; i++) {
+ ships_on_screen[i] = 0;
+ }
+
+ clrscr();
+ flushinp();
+ fight_stats(num_ships, orders);
+
+ while(num_ships > 0) {
+ status = 100 - ((damage * 100 / capacity));
+ if(status <= 0) {
+ return 4;
+ }
+ flushinp();
+ gotoxy(0, 3);
+ clrtoeol();
+
+ cputs("Current seaworthiness: ");
+ cputs(st[status / 20]);
+ cputs(" (");
+ cprintulong(status);
+ cputs("%)");
+ gotoxy(0, 4);
+ show_damage();
+
+ for(i = 0; i <= 9; i++) {
+ if (num_ships > num_on_screen) {
+ if (ships_on_screen[i] == 0) {
+ jsleep(5);
+ ships_on_screen[i] = (randi() % ec) + 20;
+ draw_lorcha(i, 0, 0);
+ num_on_screen++;
+ }
+ }
+ }
+
+ plus_or_space(num_ships > num_on_screen);
+
+ gotoxy(0, 16);
+ cputs("\r\n");
+ timed_getch(TMOUT_3S);
+
+ if(input == 'f') {
+ orders = 1;
+ } else if(input == 'r') {
+ orders = 2;
+ } else if (input == 't') {
+ orders = 3;
+ }
+
+ if(orders == 0) {
+ timed_getch(TMOUT_3S);
+
+ if (input == 'f')
+ {
+ orders = 1;
+ } else if ((input == 'R') || (input == 'r')) {
+ orders = 2;
+ } else if ((input == 'T') || (input == 't')) {
+ orders = 3;
+ } else {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("Taipan, what shall we do??\r\n(Fight, Run, Throw cargo)");
+ // timeout(-1);
+ while ((input != 'f') &&
+ (input != 'r') &&
+ (input != 't'))
+ {
+ input = lcgetch();
+ }
+ gotoxy(0, 3);
+ clrtoeol();
+ gotoxy(0, 4);
+ clrtoeol();
+ if (input == 'f') {
+ orders = 1;
+ } else if (input == 'r') {
+ orders = 2;
+ } else {
+ orders = 3;
+ }
+ }
+ }
+
+ fight_stats(num_ships, orders);
+ if((orders == 1) && (guns > 0)) {
+ static int targeted, sk;
+ sk = 0;
+
+ ok = 3;
+ ik = 1;
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("Aye, we'll fight 'em, Taipan.");
+ timed_getch(TMOUT_3S);
+
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("We're firing on 'em, Taipan!");
+ timed_getch(TMOUT_1S);
+
+ 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))
+ {
+ static int j;
+
+ for (j = 0; j <= 9; j++) {
+ if (num_ships > num_on_screen) {
+ if(ships_on_screen[j] == 0) {
+ ships_on_screen[j] = randclamp(ec) + 20;
+ draw_lorcha(j, 0, 0);
+ num_on_screen++;
+ }
+ }
+ }
+ }
+
+ plus_or_space(num_ships > num_on_screen);
+
+ gotoxy(0, 16);
+ cputc('\r');
+ cputc('\n');
+
+ targeted = randi()%10;
+ while(ships_on_screen[targeted] == 0) {
+ targeted = randi()%10;
+ }
+
+ draw_lorcha(targeted, 0, 0x80);
+ jsleep(5);
+
+ draw_lorcha(targeted, 0, 0);
+ jsleep(5);
+
+ draw_lorcha(targeted, 0, 0x80);
+ jsleep(5);
+
+ draw_lorcha(targeted, 0, 0);
+ jsleep(5);
+
+ ships_on_screen[targeted] -= randi()%30 + 10;
+
+ if(ships_on_screen[targeted] <= 0) {
+ num_on_screen--;
+ num_ships--;
+ sk++;
+ ships_on_screen[targeted] = 0;
+
+ sink_lorcha(targeted);
+
+ plus_or_space(num_ships > num_on_screen);
+ /*
+ if(num_ships == num_on_screen) {
+ gotoxy(39, 7);
+ cputc(' ');
+ }
+ */
+
+ fight_stats(num_ships, orders);
+ }
+
+ if(num_ships == 0) {
+ i += guns;
+ } else {
+ jsleep(10);
+ }
+ }
+ gotoxy(0, 3);
+ clrtoeol();
+ if(sk > 0) {
+ cputs("Sunk ");
+ cprintulong(sk);
+ cputs(" of the buggers, Taipan!");
+ } else {
+ cputs("Hit 'em, but didn't sink 'em, Taipan!");
+ }
+ timed_getch(TMOUT_3S);
+
+ // if ((randi()%s0 > (num_ships * .6 / id)) && (num_ships > 2))
+ if((randi()%s0 > ((num_ships / 2) / id)) && (num_ships > 2)) {
+ static int ran;
+ ran = randi()%(num_ships / 3 / id) + 1;
+
+ num_ships -= ran;
+ fight_stats(num_ships, orders);
+ gotoxy(0, 3);
+ clrtoeol();
+ cprintulong(ran);
+ cputs(" ran away, Taipan!");
+
+ if(num_ships <= 10) {
+ for(i = 9; i >= 0; i--) {
+ if ((num_on_screen > num_ships) && (ships_on_screen[i] > 0)) {
+ ships_on_screen[i] = 0;
+ num_on_screen--;
+
+ draw_lorcha(i, 7, 0);
+ jsleep(5);
+ }
+ }
+ if(num_ships == num_on_screen) {
+ plus_or_space(0);
+ }
+ }
+
+ gotoxy(0, 16);
+
+ timed_getch(TMOUT_3S);
+
+ if(input == 'f') {
+ orders = 1;
+ } else if(input == 'r') {
+ orders = 2;
+ } else if(input == 't') {
+ orders = 3;
+ }
+ }
+ } else if ((orders == 1) && (guns == 0)) {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("We have no guns, Taipan!!");
+ timed_getch(TMOUT_3S);
+ } else if (orders == 3) {
+ static int choice;
+ static long amount, total;
+ choice = 0;
+ amount = 0;
+ total = 0;
+
+ gotoxy(0, 18);
+ cputs("You have the following on board, Taipan:");
+ gotoxy(4, 19);
+ cputs(item[0]);
+ cputs(": ");
+ cprintulong(hold_[0]);
+ gotoxy(24, 19);
+ cputs(item[1]);
+ cputs(": ");
+ cprintulong(hold_[1]);
+ gotoxy(5, 20);
+ cputs(item[2]);
+ cputs(": ");
+ cprintulong(hold_[2]);
+ gotoxy(21, 20);
+ cputs(item[3]);
+ cputs(": ");
+ cprintulong(hold_[3]);
+
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("What shall I throw overboard, Taipan? ");
+
+ /* TODO: this, buy(), sell() have common code */
+ while ((choice != 'o') &&
+ (choice != 's') &&
+ (choice != 'a') &&
+ (choice != 'g') &&
+ (choice != '*'))
+ {
+ choice = lc(get_one());
+ }
+
+ if(choice == 'o') {
+ choice = 0;
+ } else if(choice == 's') {
+ choice = 1;
+ } else if(choice == 'a') {
+ choice = 2;
+ } else if(choice == 'g') {
+ choice = 3;
+ } else {
+ choice = 4;
+ }
+
+ if(choice < 4) {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("How much, Taipan? ");
+
+ amount = get_num(9);
+ if((hold_[choice] > 0) && ((amount == -1) || (amount > hold_[choice])))
+ {
+ amount = hold_[choice];
+ }
+ total = hold_[choice];
+ } else {
+ total = hold_[0] + hold_[1] + hold_[2] + hold_[3];
+ }
+
+ if(total > 0) {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("Let's hope we lose 'em, Taipan!");
+ if (choice < 4) {
+ hold_[choice] -= amount;
+ hold += amount;
+ ok += (amount / 10);
+ } else {
+ hold_[0] = 0;
+ hold_[1] = 0;
+ hold_[2] = 0;
+ hold_[3] = 0;
+ hold += total;
+ ok += (total / 10);
+ }
+ gotoxy(0, 18);
+ clrtobot();
+
+ timed_getch(TMOUT_3S);
+ } else {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("There's nothing there, Taipan!");
+ gotoxy(0, 18);
+ clrtobot();
+
+ timed_getch(TMOUT_3S);
+ }
+ }
+
+ if((orders == 2) || (orders == 3)) {
+ if(orders == 2) {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("Aye, we'll run, Taipan.");
+ timed_getch(TMOUT_3S);
+ }
+
+ ok += ik++;
+ if(randi()%ok > randi()%num_ships) {
+ flushinp();
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("We got away from 'em, Taipan!");
+ timed_getch(TMOUT_3S);
+ num_ships = 0;
+ } else {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("Couldn't lose 'em.");
+ timed_getch(TMOUT_3S);
+
+ if((num_ships > 2) && (randi()%5 == 0)) {
+ static int lost;
+ lost = (randi()%num_ships / 2) + 1;
+
+ num_ships -= lost;
+ fight_stats(num_ships, orders);
+ gotoxy(0, 3);
+ clrtoeol();
+ // printw("But we escaped from %d of 'em!", lost);
+ cputs("But we escaped from ");
+ cprintulong(lost);
+ cputs(" of 'em!");
+
+ if(num_ships <= 10) {
+ for(i = 9; i >= 0; i--) {
+ if((num_on_screen > num_ships) && (ships_on_screen[i] > 0)) {
+ ships_on_screen[i] = 0;
+ num_on_screen--;
+
+ draw_lorcha(i, 7, 0);
+ jsleep(5);
+ }
+ }
+ plus_or_space(num_ships > num_on_screen);
+ /*
+ if(num_ships == num_on_screen) {
+ gotoxy(39, 7);
+ cputc(' ');
+ }
+ */
+ }
+
+ gotoxy(0, 16);
+
+ timed_getch(TMOUT_3S);
+
+ if(input == 'f') {
+ orders = 1;
+ } else if(input == 'r') {
+ orders = 2;
+ } else if(input == 't') {
+ orders = 3;
+ }
+ }
+ }
+ }
+
+ if(num_ships > 0) {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("They're firing on us, Taipan!");
+
+ timed_getch(TMOUT_3S);
+ flushinp();
+
+ for(i = 0; i < 3; i++) {
+ POKE(710, 0xcc);
+ jsleep(10);
+ POKE(710, 0xc0);
+ jsleep(10);
+ }
+
+ fight_stats(num_ships, orders);
+ for(i = 0; i <= 9; i++) {
+ if(ships_on_screen[i] > 0) {
+ draw_lorcha(i, 0, 0);
+ }
+ }
+
+ plus_or_space(num_ships > num_on_screen);
+
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("We've been hit, Taipan!!");
+
+ timed_getch(TMOUT_3S);
+
+ i = (num_ships > 15) ? 15 : num_ships;
+
+ // is this really correct?
+ // if ((guns > 0) && ((randi()%100 < (((float) damage / capacity) * 100)) ||
+ // ((((float) damage / capacity) * 100) > 80)))
+
+ if((guns > 0) && ((randi()%100 < ((damage * 100) / capacity)) ||
+ (((damage * 100) / capacity)) > 80))
+ {
+ i = 1;
+ guns--;
+ hold += 10;
+ fight_stats(num_ships, orders);
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("The buggers hit a gun, Taipan!!");
+ fight_stats(num_ships, orders);
+
+ timed_getch(TMOUT_3S);
+ }
+
+ // damage = damage + ((ed * i * id) * ((float) randi() / RAND_MAX)) + (i / 2);
+ // remember, ed is now scaled by 2 (used to be 0.5, now 1)
+ // 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);
+ if(damage > capacity) damage = capacity; /* just in case */
+ if((id == GENERIC) && (randi()%20 == 0)) {
+ return 2;
+ }
+ }
+ }
+
+ if(orders == 1) {
+ clrscr();
+ fight_stats(num_ships, orders);
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("We got 'em all, Taipan!");
+ timed_getch(TMOUT_3S);
+
+ return 1;
+ } else {
+ return 3;
+ }
+}
+
+/* TODO: rewrite in asm */
+int get_one(void)
+{
+ int input,
+ choice = 0,
+ character = 0;
+
+ // Atari cursor doesn't change visibility until a character
+ // is printed... can't use cputc() here as it escapes the
+ // character (prints graphics char instead of actually backspacing)
+ putchar(' ');
+ cursor(1);
+ putchar(BKSP);
+
+ while ((input = cgetc()) != '\n')
+ {
+ if (((input == BKSP) || (input == 127)) && (character == 0))
+ {
+ } else if ((input == BKSP) || (input == 127)) {
+ putchar(BKSP);
+ character--;
+ } else if (character >= 1) {
+ } else if (input == '\33') {
+ flushinp();
+ } else {
+ putchar(input);
+ choice = input;
+ character++;
+ }
+ }
+ cursor(0);
+
+ return choice;
+}
+
+/* TODO: rewrite in asm. Maybe. */
+unsigned long get_num(int maxlen)
+{
+ /* see comment in fancy_numbers for why this is static */
+ static char number[20];
+
+ int input,
+ character = 0;
+
+ long amount;
+
+ putchar(' ');
+ cursor(1);
+ putchar(BKSP);
+ while ((input = cgetc()) != '\n')
+ {
+ if (((input == BKSP) || (input == 127)) && (character == 0))
+ {
+ } else if ((input == BKSP) || (input == 127)) {
+ putchar(BKSP);
+ number[character] = '\0';
+ character--;
+ } else if (character >= maxlen) {
+ } else if (input == '\33') {
+ flushinp();
+ } else if (((input == 'A') || (input == 'a')) &&
+ (character == 0) && (maxlen > 1)) {
+ putchar(input);
+ number[character] = input;
+ character++;
+ } else if ((input < 48) || (input > 57)) {
+ } else {
+ putchar(input);
+ number[character] = input;
+ character++;
+ }
+ }
+
+ number[character] = '\0';
+ if ((strcmp(number, "A") == 0) || (strcmp(number, "a") == 0))
+ {
+ amount = -1;
+ } else {
+ amount = strtol(number, (char **)NULL, 10);
+ }
+
+ cursor(0);
+ return amount;
+}
+
+/* TODO: rewrite in asm */
+void cash_or_guns(void)
+{
+ int choice = 0;
+
+ clrscr();
+ cputs("Do you want to start . . .\r\n\r\n");
+ cputs(" 1) With cash (and a debt)\r\n\r\n");
+ cputs(" -- or --\r\n\r\n");
+ cputs(" 2) With five guns and no cash\r\n");
+ cputs(" (But no debt!)\r\n");
+
+ while ((choice != '1') && (choice != '2'))
+ {
+ gotoxy(10, 10);
+ cursor(1);
+ cputc('?');
+ choice = get_one();
+ cursor(0);
+ }
+
+ cputc(choice);
+ if (choice == '1')
+ {
+ cash = 400;
+ debt = 5000;
+ hold = 60;
+ guns = 0;
+ li = 0;
+ bp = 10;
+ } else {
+ cash = 0;
+ debt = 0;
+ hold = 10;
+ guns = 5;
+ li = 1;
+ bp = 7;
+ }
+
+ return;
+}
+
+void set_prices(void)
+{
+ price[0] = base_price[0][port] / 2 * (randi()%3 + 1) * base_price[0][0];
+ price[1] = base_price[1][port] / 2 * (randi()%3 + 1) * base_price[1][0];
+ price[2] = base_price[2][port] / 2 * (randi()%3 + 1) * base_price[2][0];
+ price[3] = base_price[3][port] / 2 * (randi()%3 + 1) * base_price[3][0];
+ return;
+}
+
+
+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");
+
+ show_damage();
+ 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 ");
+ 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));
+ 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);
+ cprintulong(hold);
+ } else {
+ revers(1);
+ cputs("Overload");
+ revers(0);
+ }
+
+ cputsxy(16, 8, "Guns ");
+ // printw("%d", guns);
+ cprintulong(guns);
+
+ cputsxy(4, 9, "Opium ");
+ // printw("%d", hold_[0]);
+ cprintulong(hold_[0]);
+
+ cputsxy(4, 10, "Silk ");
+ // printw("%d", hold_[1]);
+ cprintulong(hold_[1]);
+
+ cputsxy(4, 11, "Arms ");
+ // printw("%d", hold_[2]);
+ cprintulong(hold_[2]);
+
+ cputsxy(4, 12, "General ");
+ // printw("%d", hold_[3]);
+ cprintulong(hold_[3]);
+
+ cputsxy(32, 2, "Date");
+ cputsxy(29, 3, "15 ");
+ 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) {
+ revers(1);
+ }
+ cputs(st[i]);
+ cputc(':');
+ cprintulong(status);
+ revers(0);
+
+ cputsxy(0, 14, "Cash: ");
+ fancy_numbers(cash, fancy_num);
+ cputs(fancy_num);
+ cputsxy(20, 14, "Bank: ");
+ fancy_numbers(bank, fancy_num);
+ cputs(fancy_num);
+}
+
+/* Unlike the Linux port, splash_intro() doesn't have to draw
+ the "programmed by" etc. text in the intro screen, as it's
+ preloaded into screen memory as a xex segment... but it
+ means splash_intro() can *only* be called by main(), once,
+ at program startup. So we don't get a 2nd splash intro
+ when answering Y to 'Play Again?".
+ Ideally, I should redefine enough graphics characters
+ that I can draw a nice ATASCII trading ship. But for
+ now I'll just draw 6 of the lorchas.
+ */
+void splash_intro(void)
+{
+ int i;
+
+ for(i=0; i<3; i++) draw_lorcha(i, 0, 0);
+ for(i=5; i<8; i++) draw_lorcha(i, 0, 0);
+
+ timed_getch(TMOUT_5M);
+
+ flushinp();
+ return;
+}
+
+void mchenry(void)
+{
+ int 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("Will ye be wanting repairs? ");
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ // int percent = ((float) damage / capacity) * 100,
+ // this is likely wrong:
+ int percent = ((damage * 100) / (capacity * 100)) * 100,
+ time = ((year - 1860) * 12) + month;
+
+ /*
+ long br = ((((60 * (time + 3) / 4) * (float) randi() / RAND_MAX) +
+ 25 * (time + 3) / 4) * capacity / 50),
+ repair_price = (br * damage) + 1,
+ amount;
+ */
+
+ long br, repair_price, amount;
+ br = ((randclamp(60 * (time + 3) / 4) + 25 * (time + 3) / 4) * capacity / 50);
+ repair_price = (br * damage) + 1;
+
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Och, 'tis a pity to be ");
+ cprintulong(percent);
+ cputs("% damaged.\r\nWe can fix yer whole ship for ");
+ cprintulong(repair_price);
+ cputs(",\r\nor make partial repairs if you wish.\r\n");
+ cputs("How much will ye spend? ");
+
+ for (;;) {
+ gotoxy(24, 21);
+ amount = get_num(9);
+ if(amount == -1) {
+ if(cash > repair_price)
+ amount = repair_price;
+ else
+ amount = cash;
+ }
+ if(amount <= cash) {
+ cash -= amount;
+ // damage -= (int)((amount / br) + .5);
+ damage -= (int)(amount / br);
+ damage = (damage < 0) ? 0 : damage;
+ port_stats();
+ break;
+ }
+ }
+ }
+
+ return;
+}
+
+void retire(void)
+{
+ compradores_report();
+ revers(1);
+ cputs(" \r\n");
+ cputs(" Y o u ' r e a \r\n");
+ cputs(" \r\n");
+ cputs(" M I L L I O N A I R E ! \r\n");
+ cputs(" \r\n");
+ revers(1);
+ timed_getch(TMOUT_5S);
+
+ final_stats();
+}
+
+void final_stats(void)
+{
+ int years = year - 1860,
+ time = ((year - 1860) * 12) + month,
+ choice = 0;
+
+ clrscr();
+ cputs("Your final status:\r\n\r\n");
+ cash = cash + bank - debt;
+ fancy_numbers(cash, fancy_num);
+ cputs("Net cash: ");
+ cputs(fancy_num);
+ cputs("\r\nShip size: ");
+ cprintulong(capacity);
+ cputs(" units with ");
+ cprintulong(guns);
+ cputs(" guns\r\n\r\n");
+ cputs("You traded for ");
+ cprintulong(years);
+ cputs(" year");
+ if (years != 1)
+ {
+ cputc('s');
+ }
+ cputs(" and ");
+ cprintulong(month);
+ cputs(" month");
+ if (month > 1)
+ {
+ cputc('s');
+ }
+ cputs("\r\n\r\n");
+ cash = cash / 100 / time;
+ revers(1);
+ cputs("Your score is ");
+ cprintulong(cash);
+ cputs(".\r\n");
+ revers(0);
+ if ((cash < 100) && (cash >= 0))
+ {
+ cputs("Have you considered a land based job?\r\n\r\n\r\n");
+ } else if (cash < 0) {
+ cputs("The crew has requested that you stay on\r\n");
+ cputs("shore for their safety!!\r\n\r\n");
+ } else {
+ cputs("\r\n\r\n\r\n");
+ }
+ cputs("Your Rating:\r\n");
+ cputs(" _______________________________\r\n");
+ cputs("|");
+ if (cash > 49999)
+ {
+ revers(1);
+ }
+ cputs("Ma Tsu");
+ revers(0);
+ cputs(" 50,000 and over |\r\n");
+ cputs("|");
+ if ((cash < 50000) && (cash > 7999))
+ {
+ revers(1);
+ }
+ cputs("Master Taipan");
+ revers(0);
+ cputs(" 8,000 to 49,999|\r\n");
+ cputs("|");
+ if ((cash < 8000) && (cash > 999))
+ {
+ revers(1);
+ }
+ cputs("Taipan");
+ revers(0);
+ cputs(" 1,000 to 7,999|\r\n");
+ cputs("|");
+ if ((cash < 1000) && (cash > 499))
+ {
+ revers(1);
+ }
+ cputs("Compradore");
+ revers(0);
+ cputs(" 500 to 999|\r\n");
+ cputs("|");
+ if (cash < 500)
+ {
+ revers(1);
+ }
+ cputs("Galley Hand");
+ revers(0);
+ cputs(" less than 500|\r\n");
+ cputs("|_______________________________|\r\n\r\n");
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ gotoxy(0, 22);
+ cputs("Play again? ");
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ bank = 0;
+ hkw_[0] = 0;
+ hkw_[1] = 0;
+ hkw_[3] = 0;
+ hkw_[4] = 0;
+ hold_[0] = 0;
+ hold_[1] = 0;
+ hold_[2] = 0;
+ hold_[3] = 0;
+ hold = 0;
+ capacity = 60;
+ damage = 0;
+ month = 1;
+ year = 1860;
+ port = 1;
+
+ // splash_intro();
+ name_firm();
+ cash_or_guns();
+ set_prices();
+
+ return;
+ }
+
+ clrscr();
+
+ exit(0);
+}
+
+void transfer(void)
+{
+ int i, in_use;
+
+ long amount = 0;
+
+ if ((hkw_[0] == 0) && (hold_[0] == 0) &&
+ (hkw_[1] == 0) && (hold_[1] == 0) &&
+ (hkw_[2] == 0) && (hold_[2] == 0) &&
+ (hkw_[3] == 0) && (hold_[3] == 0))
+ {
+ gotoxy(0, 22);
+ clrtobot();
+ cputs("You have no cargo, Taipan.\r\n");
+
+ timed_getch(TMOUT_5S);
+ return;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ if (hold_[i] > 0)
+ {
+ for (;;)
+ {
+ compradores_report();
+ cputs("How much ");
+ cputs(item[i]);
+ cputs(" shall I move\r\nto the warehouse, Taipan? ");
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = hold_[i];
+ }
+ if (amount <= hold_[i])
+ {
+ in_use = hkw_[0] + hkw_[1] + hkw_[2] + hkw_[3];
+ if ((in_use + amount) <= 10000)
+ {
+ hold_[i] -= amount;
+ hkw_[i] += amount;
+ hold += amount;
+ break;
+ } else if (in_use == 10000) {
+ gotoxy(0, 21);
+ cputs("Your warehouse is full, Taipan!");
+ } else {
+ gotoxy(0, 21);
+ cputs("Your warehouse will only hold an\r\nadditional ");
+ cprintulong(10000 - in_use);
+ cputs("%d, Taipan!");
+
+ timed_getch(TMOUT_5S);
+ }
+ } else {
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("You have only ");
+ cprintulong(hold_[i]);
+ cputs(", Taipan.\r\n");
+
+ timed_getch(TMOUT_5S);
+ }
+ }
+ port_stats();
+ }
+
+ if (hkw_[i] > 0)
+ {
+ for (;;)
+ {
+ compradores_report();
+ cputs("How much ");
+ cputs(item[i]);
+ cputs("shall I move\r\naboard ship, Taipan? ");
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = hkw_[i];
+ }
+ if (amount <= hkw_[i])
+ {
+ hold_[i] += amount;
+ hkw_[i] -= amount;
+ hold -= amount;
+ break;
+ } else {
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("You have only ");
+ cprintulong(hkw_[i]);
+ cputs(", Taipan.\r\n");
+
+ timed_getch(TMOUT_5S);
+ }
+ }
+ port_stats();
+ }
+ }
+
+ return;
+}
+
+void quit(void)
+{
+ int choice = 0,
+ result = 0;
+
+ compradores_report();
+ cputs("Taipan, do you wish me to go to:\r\n");
+ cputs("1) Hong Kong, 2) Shanghai, 3) Nagasaki,\r\n");
+ cputs("4) Saigon, 5) Manila, 6) Singapore, or\r\n");
+ cputs("7) Batavia ? ");
+
+ for (;;)
+ {
+ gotoxy(13, 21);
+ clrtobot();
+
+ choice = get_num(1);
+
+ if (choice == port)
+ {
+ cputs("\r\n\nYou're already here, Taipan.");
+ timed_getch(TMOUT_5S);
+ } else if ((choice >= 1) && (choice <= 7)) {
+ port = choice;
+ break;
+ }
+ }
+
+ at_sea();
+ captains_report();
+
+#ifdef COMBAT_TEST
+ if(1)
+#else
+ if (randi()%bp == 0)
+#endif
+ {
+ int num_ships = randi()%((capacity / 10) + guns) + 1;
+
+ if (num_ships > 9999)
+ {
+ num_ships = 9999;
+ }
+ cprintulong(num_ships);
+ cputs(" hostile ships approaching, Taipan!\r\n");
+
+ timed_getch(TMOUT_3S);
+
+ result = sea_battle(GENERIC, num_ships);
+ }
+
+ if (result == 2)
+ {
+ port_stats();
+ at_sea();
+
+ captains_report();
+ cputs("Li Yuen's fleet drove them off!");
+
+ timed_getch(TMOUT_3S);
+ }
+
+ if (((result == 0) && (randi()%(4 + (8 * li))) == 0) || (result == 2))
+ {
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Li Yuen's pirates, Taipan!!\r\n\n");
+
+ timed_getch(TMOUT_3S);
+
+ if (li > 0)
+ {
+ cputs("Good joss!! They let us be!!\r\n");
+
+ timed_getch(TMOUT_3S);
+
+ return;
+ } else {
+ int num_ships = randi()%((capacity / 5) + guns) + 5;
+
+ cprintulong(num_ships);
+ cputs("ships of Li Yuen's pirate\r\n");
+ cputs("fleet, Taipan!!\r\n");
+
+ timed_getch(TMOUT_3S);
+
+ sea_battle(LI_YUEN, num_ships);
+ }
+ }
+
+ if (result > 0)
+ {
+ port_stats();
+ at_sea();
+
+ captains_report();
+ if (result == 1)
+ {
+ fancy_numbers(booty, fancy_num);
+ cputs("We captured some booty.\r\n");
+ cputs("It's worth ");
+ cputs(fancy_num);
+ cputc('!');
+ cash += booty;
+ } else if (result == 3) {
+ cputs("We made it!");
+ } else {
+ cputs("The buggers got us, Taipan!!!\r\n");
+ cputs("It's all over, now!!!");
+
+ timed_getch(TMOUT_5S);
+
+ final_stats();
+ return;
+ }
+
+ timed_getch(TMOUT_3S);
+ }
+
+ if (randi()%10 == 0)
+ {
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Storm, Taipan!!\r\n\n");
+ timed_getch(TMOUT_3S);
+
+ if (randi()%30 == 0)
+ {
+ cputs(" I think we're going down!!\r\n\n");
+ timed_getch(TMOUT_3S);
+
+ // if (((damage / capacity * 3) * ((float) randi() / RAND_MAX)) >= 1)
+ if(randclamp(damage / capacity * 3) >= 1)
+ {
+ cputs("We're going down, Taipan!!\r\n");
+ timed_getch(TMOUT_5S);
+
+ final_stats();
+ }
+ }
+
+ cputs(" We made it!!\r\n\n");
+ timed_getch(TMOUT_3S);
+
+ if (randi()%3 == 0)
+ {
+ int orig = port;
+
+ while (port == orig)
+ {
+ port = randi()%7 + 1;
+ }
+
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("We've been blown off course\r\nto ");
+ cputs(location[port]);
+ timed_getch(TMOUT_3S);
+ }
+ }
+
+ month++;
+ if (month == 13)
+ {
+ month = 1;
+ year++;
+ ec += 10;
+ ed += 1;
+ }
+
+ /* debt calculation original formula was:
+
+ debt = debt + (debt * .1);
+
+ int-based formula is the same, except it would never
+ increase if debt is <= 10, so we fudge it with debt++
+ in that case. Which means small debts accrue interest
+ *much* faster, but that shouldn't affect gameplay much.
+ There needs to be some overflow detection though... or
+ maybe we let the overflow through, and the player can
+ think of it as Wu forgiving the debt after enough years
+ go by (or, he lost the paperwork?). Most likely though,
+ the player gets his throat cut long before the amount
+ overflows.
+
+ */
+
+ if(debt) {
+ if(debt > 10)
+ debt += (debt / 10);
+ else
+ debt++;
+ }
+
+ /* bank calculation original formula was:
+ bank = bank + (bank * .005);
+ int-based formula is the same, except when bank <= 200,
+ it's linear.
+ */
+ if(bank) {
+ if(bank > 200)
+ bank += (bank / 200);
+ else
+ bank++;
+ }
+
+ set_prices();
+
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Arriving at ");
+ cputs(location[port]);
+ cputs("...");
+ timed_getch(TMOUT_3S);
+
+ return;
+}
+
+void li_yuen_extortion(void)
+{
+ int time = ((year - 1860) * 12) + month,
+ choice = 0;
+
+ /*
+ float i = 1.8,
+ j = 0,
+ amount = 0;
+ */
+ unsigned long amount = 0;
+ unsigned int i = 2, j = 0;
+
+ if (time > 12)
+ {
+ j = randi()%(1000 * time) + (1000 * time);
+ i = 1;
+ }
+
+ // amount = ((cash / i) * ((float) randi() / RAND_MAX)) + j;
+ amount = randclamp((cash >> (i - 1))) + j;
+
+ fancy_numbers(amount, fancy_num);
+
+ compradores_report();
+ cputs("Li Yuen asks ");
+ cputs(fancy_num);
+ cputs(" in donation\r\nto the temple of Tin Hau, the Sea\r\n");
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ gotoxy(0, 20);
+ cputs("Goddess. Will you pay? ");
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ if (amount <= cash)
+ {
+ cash -= amount;
+ li = 1;
+ } else {
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Taipan, you do not have enough cash!!\r\n\r\n");
+
+ timed_getch(TMOUT_3S);
+
+ cputs("Do you want Elder Brother Wu to make up\r\n");
+ cputs("the difference for you? ");
+ choice = 0;
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ amount -= cash;
+ debt += amount;
+ cash = 0;
+ li = 1;
+
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Elder Brother has given Li Yuen the\r\n");
+ cputs("difference between what he wanted and\r\n");
+ cputs("your cash on hand and added the same\r\n");
+ cputs("amount to your debt.\r\n");
+
+ timed_getch(TMOUT_5S);
+ } else {
+ cash = 0;
+
+ cputs("Very well. Elder Brother Wu will not pay\r\n");
+ cputs("Li Yuen the difference. I would be very\r\n");
+ cputs("wary of pirates if I were you, Taipan.\r\n");
+
+ timed_getch(TMOUT_5S);
+ }
+ }
+ }
+
+ port_stats();
+
+ return;
+}
+
+void elder_brother_wu(void)
+{
+ int choice = 0;
+
+ long wu = 0;
+
+ compradores_report();
+ cputs("Do you have business with Elder Brother\r\n");
+ cputs("Wu, the moneylender? ");
+
+ for (;;)
+ {
+ gotoxy(21, 19);
+
+ choice = get_one();
+ if ((choice == 'N') || (choice == 'n') || choice == 0)
+ {
+ break;
+ } else if ((choice == 'Y') || (choice == 'y')) {
+ if (((int)cash == 0) && ((int)bank == 0) && (guns == 0) &&
+ (hold_[0] == 0) && (hkw_[0] == 0) &&
+ (hold_[1] == 0) && (hkw_[1] == 0) &&
+ (hold_[2] == 0) && (hkw_[2] == 0) &&
+ (hold_[3] == 0) && (hkw_[3] == 0))
+ {
+ int i = randi()%1500 + 500,
+ j;
+
+ wu_bailout++;
+ j = randi()%2000 * wu_bailout + 1500;
+
+ for (;;)
+ {
+ compradores_report();
+ cputs("Elder Brother is aware of your plight,\r\n");
+ cputs("Taipan. He is willing to loan you an\r\n");
+ cputs("additional ");
+ cprintulong(i);
+ cputs(" if you will pay back\r\n");
+ cprintulong(j);
+ cputs(". Are you willing, Taipan? ");
+
+ choice = get_one();
+ if ((choice == 'N') || (choice == 'n'))
+ {
+ compradores_report();
+ cputs("Very well, Taipan, the game is over!\r\n");
+
+ timed_getch(TMOUT_5S);
+
+ final_stats();
+ } else if ((choice == 'Y') || (choice == 'y')) {
+ cash += i;
+ debt += j;
+ port_stats();
+
+ compradores_report();
+ cputs("Very well, Taipan. Good joss!!\r\n");
+
+ timed_getch(TMOUT_5S);
+
+ return;
+ }
+ }
+ } else if ((cash > 0) && (debt != 0)) {
+ for (;;)
+ {
+ compradores_report();
+ cputs("How much do you wish to repay\r\n");
+ cputs("him? ");
+
+ wu = get_num(9);
+ if (wu == -1)
+ {
+ wu = cash;
+ }
+ if (wu <= cash)
+ {
+ if(wu > debt) wu = debt;
+ cash -= wu;
+ debt -= wu;
+ /* // currently debt is unsigned so the negative debt
+ // bug (or feature) is unimplemented.
+ if ((wu > debt) && (debt > 0))
+ {
+ debt -= (wu + 1);
+ } else {
+ debt -= wu;
+ }
+ */
+ break;
+ } else {
+ gotoxy(0, 18);
+ clrtobot();
+ fancy_numbers(cash, fancy_num);
+ cputs("Taipan, you only have ");
+ cputs(fancy_num);
+ cputs("\r\nin cash.\r\n");
+
+ timed_getch(TMOUT_5S);
+ }
+ }
+ }
+ port_stats();
+
+ for (;;)
+ {
+ compradores_report();
+ cputs("How much do you wish to\r\n");
+ cputs("borrow? ");
+
+ wu = get_num(9);
+ if (wu == -1)
+ {
+ wu = (cash * 2);
+ }
+ if (wu <= (cash * 2))
+ {
+ cash += wu;
+ debt += wu;
+ break;
+ } else {
+ cputs("\r\n\r\nHe won't loan you so much, Taipan!");
+
+ timed_getch(TMOUT_5S);
+ }
+ }
+ port_stats();
+
+ break;
+ }
+ }
+
+ if ((debt > 20000) && (cash > 0) && (randi()%5 == 0))
+ {
+ int num = randi()%3 + 1;
+
+ cash = 0;
+ port_stats();
+
+ compradores_report();
+ cputs("Bad joss!!\r\n");
+ cprintulong(num);
+ cputs(" of your bodyguards have been killed\r\n");
+ cputs("by cutthroats and you have been robbed\r\n");
+ cputs("of all of your cash, Taipan!!\r\n");
+
+ timed_getch(TMOUT_5S);
+ }
+
+ return;
+}
+
+void good_prices(void)
+{
+ /* see comment in fancy_numbers for why this is static */
+ static char item[14];
+
+ int i = randi()%4,
+ j = randi()%2;
+
+ if (i == 0)
+ {
+ strcpy(item, "Opium");
+ } else if (i == 1) {
+ strcpy(item, "Silk");
+ } else if (i == 2) {
+ strcpy(item, "Arms");
+ } else {
+ strcpy(item, "General Cargo");
+ }
+
+ compradores_report();
+ cputs("Taipan!! The price of ");
+ cputs(item);
+ cputs("\r\n has ");
+ if (j == 0)
+ {
+ price[i] = price[i] / 5;
+ cputs("dropped");
+ } else {
+ price[i] = price[i] * (randi()%5 + 5);
+ cputs("risen");
+ }
+ cputs(" to ");
+ cprintulong(price[i]);
+ cputs("!!\r\n");
+
+ timed_getch(TMOUT_3S);
+}
+
+int port_choices(void)
+{
+ int choice = 0;
+
+ compradores_report();
+ cputs("Taipan, present prices per unit here are"); /* NB: exactly 40 cols */
+ cputs(" Opium: Silk:\r\n");
+ cputs(" Arms: General:\r\n");
+ gotoxy(11, 19);
+ cprintulong(price[0]);
+ gotoxy(29, 19);
+ cprintulong(price[1]);
+ gotoxy(11, 20);
+ cprintulong(price[2]);
+ gotoxy(29, 20);
+ cprintulong(price[3]);
+
+ for (;;)
+ {
+ gotoxy(0, 22);
+ clrtobot();
+
+ cursor(1);
+ if (port == 1)
+ {
+ if ((cash + bank) >= 1000000)
+ {
+ cputs("Shall I Buy, Sell, Visit bank, Transfer\r\n");
+ cputs("cargo, Quit trading, or Retire? ");
+
+ choice = cgetc();
+ if ((choice == 'B') || (choice == 'b') ||
+ (choice == 'S') || (choice == 's') ||
+ (choice == 'V') || (choice == 'v') ||
+ (choice == 'T') || (choice == 't') ||
+ (choice == 'Q') || (choice == 'q') ||
+ (choice == 'R') || (choice == 'r'))
+ {
+ break;
+ }
+ } else {
+ cputs("Shall I Buy, Sell, Visit bank, Transfer\r\n");
+ cputs("cargo, or Quit trading? ");
+
+ choice = cgetc();
+ if ((choice == 'B') || (choice == 'b') ||
+ (choice == 'S') || (choice == 's') ||
+ (choice == 'V') || (choice == 'v') ||
+ (choice == 'T') || (choice == 't') ||
+ (choice == 'Q') || (choice == 'q'))
+ {
+ break;
+ }
+ }
+ } else {
+ cputs("Shall I Buy, Sell, or Quit trading? ");
+
+ choice = cgetc();
+ if ((choice == 'B') || (choice == 'b') ||
+ (choice == 'S') || (choice == 's') ||
+ (choice == 'Q') || (choice == 'q'))
+ {
+ break;
+ }
+ }
+ cursor(1);
+ }
+
+ return choice;
+}
+
+
+/* TODO: rewrite in asm, or at least better C */
+void name_firm(void)
+{
+ int input,
+ character = 0;
+
+ clrscr();
+
+ chlinexy(1, 7, 38);
+ chlinexy(1, 16, 38);
+ cvlinexy(0, 8, 8);
+ cvlinexy(39, 8, 8);
+ cputcxy(0, 7, 17); // upper left corner
+ cputcxy(0, 16, 26); // lower left corner
+ cputcxy(39, 7, 5); // upper right corner
+ cputcxy(39, 16, 3); // lower right corner
+
+ gotoxy(6, 9);
+ cputs("Taipan,");
+ gotoxy(2, 11);
+ cputs("What will you name your");
+ gotoxy(6, 13);
+ cursor(1);
+ cputs("Firm:");
+ chlinexy(12, 14, 22);
+
+ gotoxy(12, 13);
+
+ while (((input = cgetc()) != ENTER) && (character < 22))
+ {
+ if (((input == BKSP) || (input == 127)) && (character == 0))
+ {
+ // nop
+ } else if ((input == BKSP) || (input == 127)) {
+ gotox(12 + character - 1);
+ cputc(' ');
+ gotox(12 + character - 1);
+ firm[character] = '\0';
+ character--;
+ } else if (input == '\33') {
+ flushinp();
+ } else {
+ cputc(input);
+ firm[character] = input;
+ character++;
+ }
+ }
+
+ cursor(0);
+ firm[character] = '\0';
+
+ return;
+}
+
+void buy(void)
+{
+ /* see comment in fancy_numbers for why this is static */
+ // static char space[5];
+
+ int choice = 0;
+
+ long afford,
+ amount;
+
+ for (;;)
+ {
+ gotoxy(0, 22);
+ clrtobot();
+
+ cputs("What do you wish me to buy, Taipan? ");
+
+ /* TODO: buy() sell() and throwing cargo, common code in get_item() */
+ choice = lc(get_one());
+ if(choice == 'o') {
+ choice = 0;
+ break;
+ } else if (choice == 's') {
+ choice = 1;
+ break;
+ } else if (choice == 'a') {
+ choice = 2;
+ break;
+ } else if (choice == 'g') {
+ choice = 3;
+ break;
+ }
+ }
+
+ for (;;)
+ {
+ gotoxy(31, 21);
+ clrtobot();
+
+ afford = cash / price[choice];
+ revers(1);
+ cputs(" You can ");
+ revers(0);
+ gotoxy(0, 22);
+ cputs("How much ");
+ cputs(item[choice]);
+ cputs(" shall");
+ gotoxy(31, 22);
+ revers(1);
+ cputs(" afford ");
+ gotoxy(31, 23);
+ cputs(" ");
+ gotoxy(31, 23);
+
+ /* TODO: is this really right? */
+ if(afford < 100) cputc(' ');
+ if(afford < 10000) cputc(' ');
+ if(afford < 1000000) cputc(' ');
+ if(afford < 100000000) cputc(' ');
+
+ /*
+ if (afford < 100)
+ {
+ strcpy(space, " ");
+ } else if (afford < 10000) {
+ strcpy(space, " ");
+ } else if (afford < 1000000) {
+ strcpy(space, " ");
+ } else if (afford < 100000000) {
+ strcpy(space, " ");
+ } else {
+ strcpy(space, "");
+ }
+ cputs(space);
+ */
+
+ cprintulong(afford);
+ revers(0);
+
+ gotoxy(0, 23);
+ cputs("I buy, Taipan: ");
+
+ amount = get_num(9);
+ if(amount == -1) {
+ amount = afford;
+ }
+ if(amount <= afford) {
+ break;
+ }
+ }
+
+ cash -= (amount * price[choice]);
+ hold_[choice] += amount;
+ hold -= amount;
+
+ return;
+}
+
+void sell(void) {
+ int choice = 0;
+
+ long amount;
+
+ for (;;)
+ {
+ gotoxy(0, 22);
+ clrtobot();
+
+ cputs("What do you wish me to sell, Taipan? ");
+
+ /* TODO: buy() sell() and throwing cargo, common code in get_item() */
+ choice = lc(get_one());
+ if(choice == 'o') {
+ choice = 0;
+ break;
+ } else if(choice == 's') {
+ choice = 1;
+ break;
+ } else if(choice == 'a') {
+ choice = 2;
+ break;
+ } else if(choice == 'g') {
+ choice = 3;
+ break;
+ }
+ }
+
+ for (;;)
+ {
+ gotoxy(0, 22);
+ clrtobot();
+
+ cputs("How much ");
+ cputs(item[choice]);
+ cputs(" shall\r\n");
+ cputs("I sell, Taipan: ");
+
+ amount = get_num(9);
+
+ if (amount == -1)
+ {
+ amount = hold_[choice];
+ }
+ if (hold_[choice] >= amount)
+ {
+ hold_[choice] -= amount;
+ break;
+ }
+ }
+
+ cash += (amount * price[choice]);
+ hold += amount;
+
+ return;
+}
+
+void visit_bank(void)
+{
+ long amount = 0;
+
+ for (;;)
+ {
+ compradores_report();
+ cputs("How much will you deposit? ");
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = cash;
+ }
+ if (amount <= cash)
+ {
+ cash -= amount;
+ bank += amount;
+ break;
+ } else {
+ gotoxy(0, 18);
+ clrtobot();
+ fancy_numbers(cash, fancy_num);
+ cputs("Taipan, you only have ");
+ cputs(fancy_num);
+ cputs("\r\nin cash.\r\n");
+
+ timed_getch(TMOUT_5S);
+ }
+ }
+ port_stats();
+
+ for (;;)
+ {
+ compradores_report();
+ cputs("How much will you withdraw? ");
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = bank;
+ }
+ if (amount <= bank)
+ {
+ cash += amount;
+ bank -= amount;
+ break;
+ } else {
+ fancy_numbers(cash, fancy_num);
+ cputs("Taipan, you only have ");
+ cputs(fancy_num);
+ cputs("\r\nin the bank.");
+
+ timed_getch(TMOUT_5S);
+ }
+ }
+ port_stats();
+
+ return;
+}
+
+/*
+void debttest() {
+ int i;
+
+ debt = 1;
+
+ for(i=0; i<20; i++) {
+ debt = debt + (debt >> 8) + (debt >> 10);
+ // debt = debt + (debt >> 4) + (debt >> 5) + (debt >> 7) - (debt >> 9); // debt *= 0.09961
+ printf("%lu\n", debt);
+ }
+
+ cgetc();
+ clrscr();
+ debt = 1;
+
+ for(i=0; i<20; i++) {
+ if(debt > 200)
+ debt += (debt / 200);
+ else
+ debt++;
+
+ printf("%lu\n", debt);
+ }
+ cgetc();
+
+}
+*/
+
+/* N.B. cc65 is perfectly OK with main(void), and it avoids
+ warnings about argv/argc unused. */
+int main(void) {
+ int choice;
+
+ /*
+ {
+ int status;
+ capacity = 60;
+ damage = 47;
+ status = 100 - ((damage * 100) / capacity);
+ cprintulong(status);
+hang: goto hang;
+ }
+ */
+
+ /*
+ _randomize();
+ while(1) {
+ clrscr();
+ cprintulong(randi());
+ cputs("\r\n");
+ cprintulong(rand());
+ cgetc();
+ }
+ */
+
+ // fancytest();
+ // debttest();
+ atari_text_setup();
+ initrand();
+ splash_intro();
+ name_firm();
+ cash_or_guns();
+ set_prices();
+
+ for (;;)
+ {
+ choice = 0;
+
+ port_stats();
+
+ if ((port == 1) && (li == 0) && (cash > 0))
+ {
+ li_yuen_extortion();
+ }
+
+ if ((port == 1) && (damage > 0))
+ {
+ mchenry();
+ }
+
+ if ((port == 1) && (debt >= 10000) && (wu_warn == 0))
+ {
+ int braves = randi()%100 + 50;
+
+ compradores_report();
+ cputs("Elder Brother Wu has sent ");
+ cprintulong(braves);
+ cputs(" braves\r\n");
+ cputs("to escort you to the Wu mansion, Taipan.\r\n");
+
+ timed_getch(TMOUT_3S);
+
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Elder Brother Wu reminds you of the\r\n");
+ cputs("Confucian ideal of personal worthiness,\r\n");
+ cputs("and how this applies to paying one's\r\n");
+ cputs("debts.\r\n");
+
+ timed_getch(TMOUT_3S);
+
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("He is reminded of a fabled barbarian\r\n");
+ cputs("who came to a bad end, after not caring\r\n");
+ cputs("for his obligations.\r\n\r\n");
+ cputs("He hopes no such fate awaits you, his\r\n");
+ cputs("friend, Taipan.\r\n");
+
+ timed_getch(TMOUT_5S);
+
+ wu_warn = 1;
+ }
+
+ if (port == 1)
+ {
+ elder_brother_wu();
+ }
+
+ if (randi()%4 == 0)
+ {
+ if (randi()%2 == 0)
+ {
+ new_ship();
+ } else if (guns < 1000) {
+ new_gun();
+ }
+ }
+
+ if ((port != 1) && (randi()%18 == 0) && (hold_[0] > 0))
+ {
+ // float fine = ((cash / 1.8) * ((float) randi() / RAND_MAX)) + 1;
+ // the 1.8 is now a 2
+ unsigned long fine = randclamp(cash >> 1) + 1;
+
+ hold += hold_[0];
+ hold_[0] = 0;
+ cash -= fine;
+
+ port_stats();
+
+ fancy_numbers(fine, fancy_num);
+ compradores_report();
+ cputs("Bad Joss!!\r\n");
+ cputs("The local authorities have seized your\r\n");
+ cputs("Opium cargo and have also fined you\r\n");
+ cputs(fancy_num);
+ cputs(", Taipan!\r\n");
+
+ timed_getch(TMOUT_5S);
+ }
+
+ if ((randi()%50 == 0) &&
+ ((hkw_[0] + hkw_[1] + hkw_[2] + hkw_[3]) > 0))
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ // hkw_[i] = ((hkw_[i] / 1.8) * ((float) randi() / RAND_MAX));
+ // the 1.8 is now a 2
+ hkw_[i] = randclamp(hkw_[i] >> 1);
+ }
+
+ port_stats();
+
+ compradores_report();
+ cputs("Messenger reports large theft\r\n");
+ cputs("from warehouse, Taipan.\r\n");
+
+ timed_getch(TMOUT_5S);
+ }
+
+ if (randi()%20 == 0)
+ {
+ if (li > 0) { li++; }
+ if (li == 4) { li = 0; }
+ }
+
+ if ((port != 1) && (li == 0) && (randi()%4 != 0))
+ {
+ compradores_report();
+ cputs("Li Yuen has sent a Lieutenant,\r\n");
+ cputs("Taipan. He says his admiral wishes\r\n");
+ cputs("to see you in Hong Kong, posthaste!\r\n");
+
+ timed_getch(TMOUT_3S);
+ }
+
+ if (randi()%9 == 0)
+ {
+ good_prices();
+ }
+
+ if ((cash > 25000) && (randi()%20 == 0))
+ {
+ // float robbed = ((cash / 1.4) * ((float) randi() / RAND_MAX));
+ // line below changes the 1.4 to 1.5
+ unsigned long robbed = randclamp((cash >> 2) + (cash >> 1));
+
+ cash -= robbed;
+ port_stats();
+
+ fancy_numbers(robbed, fancy_num);
+ compradores_report();
+ cputs("Bad Joss!!\r\n");
+ cputs("You've been beaten up and\r\n");
+ cputs("robbed of ");
+ cputs(fancy_num);
+ cputs(" in cash, Taipan!!\r\n");
+
+ timed_getch(TMOUT_5S);
+ }
+
+ for (;;)
+ {
+ while ((choice != 'Q') && (choice != 'q'))
+ {
+ switch (choice = port_choices())
+ {
+ case 'B':
+ case 'b':
+ buy();
+ break;
+
+ case 'S':
+ case 's':
+ sell();
+ break;
+
+ case 'V':
+ case 'v':
+ visit_bank();
+ break;
+
+ case 'T':
+ case 't':
+ transfer();
+ break;
+
+ case 'R':
+ case 'r':
+ retire();
+ }
+
+ port_stats();
+ }
+
+ choice = 0;
+ if (hold >= 0)
+ {
+ quit();
+ break;
+ } else {
+ overload();
+ }
+ }
+ }
+
+ cgetc();
+ POKE(709, 0);
+hangmain:
+ goto hangmain;
+ return 0;
+}
diff --git a/taipan.c_before_timed_getch b/taipan.c_before_timed_getch
new file mode 100644
index 0000000..7b399eb
--- /dev/null
+++ b/taipan.c_before_timed_getch
@@ -0,0 +1,2877 @@
+#include <conio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <peekpoke.h>
+
+/* define this for testing sea_battle(). it causes a pirate
+ attack every time you leave port. Don't leave defined for
+ a relese!! */
+// #define COMBAT_TEST
+
+/**** atari-specific stuff */
+
+/* values returned by cgetc() for backspace & enter keys */
+#define BKSP 0x7e
+#define ENTER 0x9b
+
+/* timed_getch() args for seconds, based on jiffy clock of
+ target system. No adjustment made for PAL, sorry. */
+#define TMOUT_1S 60
+#define TMOUT_3S 180
+#define TMOUT_5S 300
+
+/* original plan was to use time() or _systime(). It turns out that
+ these are not implemented on the Atari, and always return -1.
+ So, use the OS's countdown timer instead.
+ Anyone porting to another cc65 platform needs to rewrite this.
+
+ TODO: rewrite in terms of clock() and CLOCKS_PER_SEC. Will make it
+ less atari-specific, plus auto-adjust for pal/ntsc.
+
+ TODO: there is atari-specific stuff elsewhere in the code :(
+ */
+
+static unsigned int tmout_jiffies = 0;
+
+void timeout(unsigned int msec) {
+ if(msec > 0)
+ tmout_jiffies = (msec / 100) * 6; // TODO: should be 5 for PAL
+ else
+ tmout_jiffies = 0;
+}
+
+/* set timer with interrupts disabled, to avoid race condition
+ where an interrupt happens between setting the high & low bytes. */
+void start_timer() {
+ __asm__("SEI");
+ POKE(541, tmout_jiffies / 256);
+ POKE(540, tmout_jiffies % 256);
+ __asm__("CLI");
+}
+
+#define timer_running() (PEEK(541) || PEEK(540))
+#define timer_expired() (!timer_running())
+
+int flushinp() {
+ POKE(764, 255);
+ return 0;
+}
+
+void atari_text_setup() {
+ POKE(710, 0xc0); // green background
+ POKE(709, 0x0c); // bright text
+ POKE(756, 0xb8); // use our custom font
+}
+
+void jsleep(unsigned int jiffies) {
+ tmout_jiffies = jiffies;
+ start_timer();
+ while(timer_running())
+ ;
+ timeout(-1);
+}
+
+
+/* Atari-specific random number functions from rand.s.
+ Non-Atari platforms can probably just:
+#define initrand() _randomize();
+#define randi() rand();
+#define randl() (unsigned long)((randi() << 16) | randi())
+*/
+
+#define initrand() /* no-op on Atari */
+extern unsigned int __fastcall__ randi(void);
+extern unsigned long __fastcall__ randl(void);
+
+/* used to use this:
+unsigned long randl() {
+ unsigned long r = rand();
+ char *buf = (char *)r;
+ buf[2] = PEEK(53770);
+ buf[3] = PEEK(53770);
+ return r;
+}
+*/
+
+
+/**** End of atari-specific stuff */
+
+unsigned long randclamp(unsigned long clamp) {
+ return randl() % clamp;
+}
+
+/* TODO: rewrite in asm */
+void clrtobot() {
+ unsigned char rows, cols, y, oldx, oldy;
+ oldx = wherex();
+ oldy = wherey();
+ screensize(&cols, &rows);
+ cclear(cols - wherex()); /* leaves cursor at start of next line */
+ for(y = wherey(); y < rows; y++)
+ cclearxy(0, y, cols);
+ gotoxy(oldx, oldy);
+}
+
+/* TODO: rewrite in asm */
+void clrtoeol() {
+ unsigned char cols, rows, oldx, oldy;
+ oldx = wherex();
+ oldy = wherey();
+ screensize(&cols, &rows);
+ cclear(cols - wherex());
+ gotoxy(oldx, oldy);
+}
+
+/* TODO: rewrite in asm */
+/* this getch() works like curses, except it always acts
+ like it's in cbreak mode. */
+int getch() {
+ int ret = -1;
+
+ if(tmout_jiffies == 0) return cgetc();
+
+ start_timer();
+
+ do {
+ if(kbhit()) {
+ ret = cgetc();
+ break;
+ }
+ } while (timer_running());
+
+ return ret;
+}
+
+/* TODO: rewrite in asm */
+int lc(int a) {
+ if(a >= 'A' && a <= 'Z') a ^= 0x20;
+ return a;
+}
+
+/* TODO: rewrite in asm */
+/* wrapper for getch() that returns letters as lowercase only
+ (and everything else normally). Avoids a bunch of reduntant
+ if(foo == 'A' || foo == 'a') tests. */
+int lcgetch() {
+ return lc(getch());
+}
+
+/* taipan functions (modified as little as possible) */
+#define GENERIC 1
+#define LI_YUEN 2
+
+void splash_intro(void);
+int get_one(void);
+unsigned long get_num(int maxlen);
+void name_firm(void);
+void cash_or_guns(void);
+void set_prices(void);
+void port_stats(void);
+int port_choices(void);
+void new_ship(void);
+void new_gun(void);
+void li_yuen_extortion(void);
+void elder_brother_wu(void);
+void good_prices(void);
+void buy(void);
+void sell(void);
+void visit_bank(void);
+void transfer(void);
+void quit(void);
+void overload(void);
+void fancy_numbers(unsigned long num, char *fancy);
+int sea_battle(int id, int num_ships);
+extern void __fastcall__ draw_lorcha(int which, int displacement, int mask);
+void clear_lorcha(int x, int y);
+void draw_blast(int x, int y);
+void sink_lorcha(int which);
+void fight_stats(int ships, int orders);
+void mchenry(void);
+void retire(void);
+void final_stats(void);
+
+char firm[23],
+ fancy_num[24];
+
+char *item[] = { "Opium", "Silk", "Arms", "General Cargo" };
+
+char *location[] = { "At sea", "Hong Kong", "Shanghai", "Nagasaki",
+ "Saigon", "Manila", "Singapore", "Batavia" };
+
+char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+char *st[] = { "Critical", " Poor", " Fair",
+ " Good", " Prime", "Perfect" };
+
+unsigned long cash = 0,
+ bank = 0,
+ debt = 0,
+ booty = 0,
+ ec = 20,
+ ed = 1; // used to be a float, 0.5
+
+unsigned long price[4];
+
+int base_price[4][8] = { {1000, 11, 16, 15, 14, 12, 10, 13},
+ {100, 11, 14, 15, 16, 10, 13, 12},
+ {10, 12, 16, 10, 11, 13, 14, 15},
+ {1, 10, 11, 12, 13, 14, 15, 16} };
+
+int hkw_[4],
+ hold_[4];
+
+int hold = 0,
+ capacity = 60,
+ guns = 0,
+ bp = 0,
+ damage = 0,
+ month = 1,
+ year = 1860,
+ li = 0,
+ port = 1,
+ wu_warn = 0,
+ wu_bailout = 0;
+
+/* print an int or long as a string, conio-style */
+void cprintulong(unsigned long ul) {
+ cputs(ultoa(ul, fancy_num, 10));
+}
+
+#ifdef COMBAT_TEST
+void show_damage(void) {
+ cputc(' ');
+ cprintulong(damage);
+ cputc('/');
+ cprintulong(capacity);
+}
+#else
+#define show_damage()
+#endif
+
+// fancy_numbers() will get replaced sooner or later.
+// void cprintfancy(unsigned long ul) {
+// }
+
+void at_sea() {
+ gotoxy(30, 6);
+ cputc(' ');
+ revers(1);
+ cputs(location[0]);
+ revers(0);
+ cputc(' ');
+ cputc(' ');
+}
+
+/* this bit of code was duplicated a *bunch* of times,
+ making it a function makes the binary 2K smaller. */
+
+void prepare_report() {
+ gotoxy(0, 16);
+ clrtobot();
+}
+
+void compradores_report() {
+ prepare_report();
+ cputs("Comprador's Report\r\n\n");
+}
+
+void captains_report() {
+ prepare_report();
+ cputs(" Captain's Report\r\n\n");
+}
+
+
+void overload(void)
+{
+ compradores_report();
+ cputs("Your ship is overloaded, Taipan!!");
+ timeout(5000);
+ getch();
+ timeout(-1);
+ return;
+}
+
+void new_ship(void)
+{
+ int choice = 0,
+ time;
+
+ // float amount;
+ unsigned long amount;
+
+ time = ((year - 1860) * 12) + month;
+ amount = randi()%(1000 * (time + 5) / 6) * (capacity / 50) + 1000;
+
+ if (cash < amount)
+ {
+ return;
+ }
+
+ fancy_numbers(amount, fancy_num);
+
+ compradores_report();
+ cputs("Do you wish to trade in your ");
+ if (damage > 0)
+ {
+ revers(1);
+ cputs("damaged");
+ revers(0);
+ } else {
+ cputs("fine");
+ }
+ cputs("\r\nship for one with 50 more capacity by\r\n");
+ cputs("paying an additional ");
+ cputs(fancy_num);
+ cputs(", Taipan? ");
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ cash -= amount;
+ hold += 50;
+ capacity += 50;
+ damage = 0;
+ }
+
+ if ((randi()%2 == 0) && (guns < 1000))
+ {
+ port_stats();
+ new_gun();
+ }
+
+ port_stats();
+
+ return;
+}
+
+void new_gun(void)
+{
+ int choice = 0,
+ time;
+
+ unsigned long amount;
+
+ time = ((year - 1860) * 12) + month;
+ amount = randi()%(1000 * (time + 5) / 6) + 500;
+
+ if ((cash < amount) || (hold < 10))
+ {
+ return;
+ }
+
+ fancy_numbers(amount, fancy_num);
+
+ compradores_report();
+ cputs("Do you wish to buy a ship's gun\r\n for ");
+ cputs(fancy_num);
+ cputs(", Taipan? ");
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ cash -= amount;
+ hold -= 10;
+ guns += 1;
+ }
+
+ port_stats();
+
+ return;
+}
+
+void fancy_numbers(unsigned long num, char *fancy)
+{
+ /* note to self: find out why there's graphic corruption
+ if this isn't static. It's caused by sprintf() or strcpy()
+ writing to the font, which is supposed to be above cc65's max
+ usable address! */
+ static char number[18];
+ char mil = 0;
+ unsigned int num1, num2;
+
+ if (num >= 100000000L)
+ {
+ num1 = (num / 1000000L);
+ ultoa(num1, fancy, 10);
+ mil = 1;
+ } else if (num >= 10000000L) {
+ num1 = (num / 1000000L);
+ num2 = ((num % 1000000L) / 100000L);
+ ultoa(num1, fancy, 10);
+ if (num2 > 0)
+ {
+ strcat(fancy, ".");
+ ultoa(num2, number, 10);
+ strcat(fancy, number);
+ }
+ mil = 1;
+ } else if (num >= 1000000L) {
+ num1 = (num / 1000000L);
+ num2 = ((num % 1000000L) / 10000L);
+ ultoa(num1, fancy, 10);
+ if (num2 > 0)
+ {
+ strcat(fancy, ".");
+ ultoa(num2, number, 10);
+ strcat(fancy, number);
+ }
+ mil = 1;
+ } else {
+ ultoa(num, fancy, 10);
+ }
+
+ if(mil) strcat(fancy, " Million");
+}
+
+/*
+void fancytest(void) {
+ fancy_numbers(1000, fancy_num);
+ cputs(fancy_num);
+ cputs("\r\n");
+ fancy_numbers(10000, fancy_num);
+ cputs(fancy_num);
+ cputs("\r\n");
+ fancy_numbers(100000, fancy_num);
+ cputs(fancy_num);
+ cputs("\r\n");
+ fancy_numbers(1000000, fancy_num);
+ cputs(fancy_num);
+ cputs("\r\n");
+ fancy_numbers(4294967295, fancy_num); // LONG_MAX
+ cputs(fancy_num);
+ cputs("\r\n");
+ cgetc();
+}
+*/
+
+void fight_stats(int ships, int orders)
+{
+ // char ch_orders[12];
+
+ /*
+ if (orders == 0)
+ {
+ strcpy(ch_orders, "\0");
+ } else if (orders == 1) {
+ strcpy(ch_orders, "Fight ");
+ } else if (orders == 2) {
+ strcpy(ch_orders, "Run ");
+ } else {
+ strcpy(ch_orders, "Throw Cargo");
+ }
+ */
+
+ gotoxy(0, 0);
+
+ /*
+ if (ships >= 1000)
+ {
+ printw("%d", ships);
+ } else if (ships >= 100) {
+ printw(" %d", ships);
+ } else if (ships >= 10) {
+ printw(" %d", ships);
+ } else {
+ printw(" %d", ships);
+ }
+ */
+
+ if(ships < 1000) cputc(' ');
+ if(ships < 100) cputc(' ');
+ if(ships < 10) cputc(' ');
+ cprintulong(ships);
+
+ // gotoxy(0, 5);
+ cputs(" ship");
+ if(ships != 1) cputc('s');
+ cputs(" attacking, Taipan! \r\n");
+
+ /*
+ if (ships == 1)
+ {
+ printw("ship attacking, Taipan! \n");
+ } else {
+ printw("ships attacking, Taipan!\n");
+ }
+ */
+
+ // printw("Your orders are to: %s", ch_orders);
+ cputs("Your orders are to: ");
+ if(orders == 1)
+ cputs("Fight ");
+ else if(orders == 2)
+ cputs("Run ");
+ else if(orders == 3)
+ cputs("Throw Cargo");
+
+ /*
+ move(0, 50);
+ printw("| We have");
+ move(1, 50);
+ printw("| %d guns", guns);
+ move(2, 50);
+ printw("----------");
+ move(16, 0);
+ */
+
+ revers(1);
+ gotoxy(30, 0);
+ cputs(" We have");
+ gotoxy(30, 1);
+ cputc(' ');
+ if(guns < 1000) cputc(' ');
+ if(guns < 100) cputc(' ');
+ if(guns < 10) cputc(' ');
+ cprintulong(guns);
+ cputs(" guns");
+ revers(0);
+ return;
+}
+
+void sink_lorcha(int which) {
+ int i;
+ for(i = 1; i < 8; i++) {
+ draw_lorcha(which, i, 0);
+ jsleep(5);
+ }
+}
+
+/* print an inverse video plus if there are offscreen ships,
+ or clear it to a space if not. */
+void plus_or_space(unsigned char b) {
+ gotoxy(39, 15);
+ cputc(b ? 0xab : ' ');
+}
+
+int sea_battle(int 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 orders,
+ num_on_screen,
+ time,
+ s0,
+ ok,
+ ik,
+ i,
+ input,
+ status;
+
+ orders = 0;
+ num_on_screen = 0;
+ time = ((year - 1860) * 12) + month;
+ s0 = num_ships;
+ ok = 0;
+ ik = 1;
+
+ booty = (time / 4 * 1000 * num_ships) + randi()%1000 + 250;
+
+ for(i = 0; i <= 9; i++) {
+ ships_on_screen[i] = 0;
+ }
+
+ clrscr();
+ flushinp();
+ fight_stats(num_ships, orders);
+
+ while(num_ships > 0) {
+ status = 100 - ((damage * 100 / capacity));
+ if(status <= 0) {
+ return 4;
+ }
+ flushinp();
+ gotoxy(0, 3);
+ clrtoeol();
+
+ cputs("Current seaworthiness: ");
+ cputs(st[status / 20]);
+ cputs(" (");
+ cprintulong(status);
+ cputs("%)");
+ gotoxy(0, 4);
+ show_damage();
+
+ for(i = 0; i <= 9; i++) {
+ if (num_ships > num_on_screen) {
+ if (ships_on_screen[i] == 0) {
+ jsleep(5);
+ ships_on_screen[i] = (randi() % ec) + 20;
+ draw_lorcha(i, 0, 0);
+ num_on_screen++;
+ }
+ }
+ }
+
+ plus_or_space(num_ships > num_on_screen);
+
+ gotoxy(0, 16);
+ cputs("\r\n");
+ timeout(3000);
+ input = lcgetch();
+ timeout(-1);
+
+ if(input == 'f') {
+ orders = 1;
+ } else if(input == 'r') {
+ orders = 2;
+ } else if (input == 't') {
+ orders = 3;
+ }
+
+ if(orders == 0) {
+ timeout(3000);
+ input = lcgetch();
+ timeout(-1);
+
+ if (input == 'f')
+ {
+ orders = 1;
+ } else if ((input == 'R') || (input == 'r')) {
+ orders = 2;
+ } else if ((input == 'T') || (input == 't')) {
+ orders = 3;
+ } else {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("Taipan, what shall we do??\r\n(f=fight, r=run, t=throw cargo)");
+ timeout(-1);
+ while ((input != 'f') &&
+ (input != 'r') &&
+ (input != 't'))
+ {
+ input = lcgetch();
+ }
+ gotoxy(0, 3);
+ clrtoeol();
+ gotoxy(0, 4);
+ clrtoeol();
+ if (input == 'f') {
+ orders = 1;
+ } else if (input == 'r') {
+ orders = 2;
+ } else {
+ orders = 3;
+ }
+ }
+ }
+
+ fight_stats(num_ships, orders);
+ if((orders == 1) && (guns > 0)) {
+ static int targeted, sk;
+ sk = 0;
+
+ ok = 3;
+ ik = 1;
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("Aye, we'll fight 'em, Taipan.");
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("We're firing on 'em, Taipan!");
+ timeout(1000);
+ input = getch();
+ timeout(-1);
+
+ 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))
+ {
+ static int j;
+
+ for (j = 0; j <= 9; j++) {
+ if (num_ships > num_on_screen) {
+ if(ships_on_screen[j] == 0) {
+ ships_on_screen[j] = randclamp(ec) + 20;
+ draw_lorcha(j, 0, 0);
+ num_on_screen++;
+ }
+ }
+ }
+ }
+
+ plus_or_space(num_ships > num_on_screen);
+
+ gotoxy(0, 16);
+ cputc('\r');
+ cputc('\n');
+
+ targeted = randi()%10;
+ while(ships_on_screen[targeted] == 0) {
+ targeted = randi()%10;
+ }
+
+ draw_lorcha(targeted, 0, 0x80);
+ jsleep(5);
+
+ draw_lorcha(targeted, 0, 0);
+ jsleep(5);
+
+ draw_lorcha(targeted, 0, 0x80);
+ jsleep(5);
+
+ draw_lorcha(targeted, 0, 0);
+ jsleep(5);
+
+ ships_on_screen[targeted] -= randi()%30 + 10;
+
+ if(ships_on_screen[targeted] <= 0) {
+ num_on_screen--;
+ num_ships--;
+ sk++;
+ ships_on_screen[targeted] = 0;
+
+ sink_lorcha(targeted);
+
+ plus_or_space(num_ships > num_on_screen);
+ /*
+ if(num_ships == num_on_screen) {
+ gotoxy(39, 7);
+ cputc(' ');
+ }
+ */
+
+ fight_stats(num_ships, orders);
+ }
+
+ if(num_ships == 0) {
+ i += guns;
+ } else {
+ jsleep(10);
+ }
+ }
+ gotoxy(0, 3);
+ clrtoeol();
+ if(sk > 0) {
+ cputs("Sunk ");
+ cprintulong(sk);
+ cputs(" of the buggers, Taipan!");
+ } else {
+ cputs("Hit 'em, but didn't sink 'em, Taipan!");
+ }
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+
+ // if ((randi()%s0 > (num_ships * .6 / id)) && (num_ships > 2))
+ if((randi()%s0 > ((num_ships / 2) / id)) && (num_ships > 2)) {
+ static int ran;
+ ran = randi()%(num_ships / 3 / id) + 1;
+
+ num_ships -= ran;
+ fight_stats(num_ships, orders);
+ gotoxy(0, 3);
+ clrtoeol();
+ cprintulong(ran);
+ cputs(" ran away, Taipan!");
+
+ if(num_ships <= 10) {
+ for(i = 9; i >= 0; i--) {
+ if ((num_on_screen > num_ships) && (ships_on_screen[i] > 0)) {
+ ships_on_screen[i] = 0;
+ num_on_screen--;
+
+ draw_lorcha(i, 7, 0);
+ jsleep(5);
+ }
+ }
+ if(num_ships == num_on_screen) {
+ plus_or_space(0);
+ }
+ }
+
+ gotoxy(0, 16);
+
+ timeout(3000);
+ input = lcgetch();
+ timeout(-1);
+
+ if(input == 'f') {
+ orders = 1;
+ } else if(input == 'r') {
+ orders = 2;
+ } else if(input == 't') {
+ orders = 3;
+ }
+ }
+ } else if ((orders == 1) && (guns == 0)) {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("We have no guns, Taipan!!");
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ } else if (orders == 3) {
+ static int choice;
+ static long amount, total;
+ choice = 0;
+ amount = 0;
+ total = 0;
+
+ gotoxy(0, 18);
+ cputs("You have the following on board, Taipan:");
+ gotoxy(4, 19);
+ cputs(item[0]);
+ cputs(": ");
+ cprintulong(hold_[0]);
+ gotoxy(24, 19);
+ cputs(item[1]);
+ cputs(": ");
+ cprintulong(hold_[1]);
+ gotoxy(5, 20);
+ cputs(item[2]);
+ cputs(": ");
+ cprintulong(hold_[2]);
+ gotoxy(21, 20);
+ cputs(item[3]);
+ cputs(": ");
+ cprintulong(hold_[3]);
+
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("What shall I throw overboard, Taipan? ");
+
+ /* TODO: this, buy(), sell() have common code */
+ while ((choice != 'o') &&
+ (choice != 's') &&
+ (choice != 'a') &&
+ (choice != 'g') &&
+ (choice != '*'))
+ {
+ choice = lc(get_one());
+ }
+
+ if(choice == 'o') {
+ choice = 0;
+ } else if(choice == 's') {
+ choice = 1;
+ } else if(choice == 'a') {
+ choice = 2;
+ } else if(choice == 'g') {
+ choice = 3;
+ } else {
+ choice = 4;
+ }
+
+ if(choice < 4) {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("How much, Taipan? ");
+
+ amount = get_num(9);
+ if((hold_[choice] > 0) && ((amount == -1) || (amount > hold_[choice])))
+ {
+ amount = hold_[choice];
+ }
+ total = hold_[choice];
+ } else {
+ total = hold_[0] + hold_[1] + hold_[2] + hold_[3];
+ }
+
+ if(total > 0) {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("Let's hope we lose 'em, Taipan!");
+ if (choice < 4) {
+ hold_[choice] -= amount;
+ hold += amount;
+ ok += (amount / 10);
+ } else {
+ hold_[0] = 0;
+ hold_[1] = 0;
+ hold_[2] = 0;
+ hold_[3] = 0;
+ hold += total;
+ ok += (total / 10);
+ }
+ gotoxy(0, 18);
+ clrtobot();
+
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ } else {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("There's nothing there, Taipan!");
+ gotoxy(0, 18);
+ clrtobot();
+
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ }
+ }
+
+ if((orders == 2) || (orders == 3)) {
+ if(orders == 2) {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("Aye, we'll run, Taipan.");
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ }
+
+ ok += ik++;
+ if(randi()%ok > randi()%num_ships) {
+ flushinp();
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("We got away from 'em, Taipan!");
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ num_ships = 0;
+ } else {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("Couldn't lose 'em.");
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+
+ if((num_ships > 2) && (randi()%5 == 0)) {
+ static int lost;
+ lost = (randi()%num_ships / 2) + 1;
+
+ num_ships -= lost;
+ fight_stats(num_ships, orders);
+ gotoxy(0, 3);
+ clrtoeol();
+ // printw("But we escaped from %d of 'em!", lost);
+ cputs("But we escaped from ");
+ cprintulong(lost);
+ cputs(" of 'em!");
+
+ if(num_ships <= 10) {
+ for(i = 9; i >= 0; i--) {
+ if((num_on_screen > num_ships) && (ships_on_screen[i] > 0)) {
+ ships_on_screen[i] = 0;
+ num_on_screen--;
+
+ draw_lorcha(i, 7, 0);
+ jsleep(5);
+ }
+ }
+ plus_or_space(num_ships > num_on_screen);
+ /*
+ if(num_ships == num_on_screen) {
+ gotoxy(39, 7);
+ cputc(' ');
+ }
+ */
+ }
+
+ gotoxy(0, 16);
+
+ timeout(3000);
+ input = lcgetch();
+ timeout(-1);
+
+ if(input == 'f') {
+ orders = 1;
+ } else if(input == 'r') {
+ orders = 2;
+ } else if(input == 't') {
+ orders = 3;
+ }
+ }
+ }
+ }
+
+ if(num_ships > 0) {
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("They're firing on us, Taipan!");
+
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ flushinp();
+
+ for(i = 0; i < 3; i++) {
+ POKE(710, 0xcc);
+ jsleep(10);
+ POKE(710, 0xc0);
+ jsleep(10);
+ }
+
+ fight_stats(num_ships, orders);
+ for(i = 0; i <= 9; i++) {
+ if(ships_on_screen[i] > 0) {
+ draw_lorcha(i, 0, 0);
+ }
+ }
+
+ plus_or_space(num_ships > num_on_screen);
+
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("We've been hit, Taipan!!");
+
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+
+ i = (num_ships > 15) ? 15 : num_ships;
+
+ // is this really correct?
+ // if ((guns > 0) && ((randi()%100 < (((float) damage / capacity) * 100)) ||
+ // ((((float) damage / capacity) * 100) > 80)))
+
+ if((guns > 0) && ((randi()%100 < ((damage * 100) / capacity)) ||
+ (((damage * 100) / capacity)) > 80))
+ {
+ i = 1;
+ guns--;
+ hold += 10;
+ fight_stats(num_ships, orders);
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("The buggers hit a gun, Taipan!!");
+ fight_stats(num_ships, orders);
+
+ timeout(3000);
+ input = getch();
+ timeout(-1);
+ }
+
+ // damage = damage + ((ed * i * id) * ((float) randi() / RAND_MAX)) + (i / 2);
+ // remember, ed is now scaled by 2 (used to be 0.5, now 1)
+ // 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);
+ if(damage > capacity) damage = capacity; /* just in case */
+ if((id == GENERIC) && (randi()%20 == 0)) {
+ return 2;
+ }
+ }
+ }
+
+ if(orders == 1) {
+ clrscr();
+ fight_stats(num_ships, orders);
+ gotoxy(0, 3);
+ clrtoeol();
+ cputs("We got 'em all, Taipan!");
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ return 1;
+ } else {
+ return 3;
+ }
+}
+
+/* TODO: rewrite in asm */
+int get_one(void)
+{
+ int input,
+ choice = 0,
+ character = 0;
+
+ // Atari cursor doesn't change visibility until a character
+ // is printed... can't use cputc() here as it escapes the
+ // character (prints graphics char instead of actually backspacing)
+ putchar(' ');
+ cursor(1);
+ putchar(BKSP);
+
+ while ((input = getch()) != '\n')
+ {
+ if (((input == BKSP) || (input == 127)) && (character == 0))
+ {
+ } else if ((input == BKSP) || (input == 127)) {
+ putchar(BKSP);
+ character--;
+ } else if (character >= 1) {
+ } else if (input == '\33') {
+ flushinp();
+ } else {
+ putchar(input);
+ choice = input;
+ character++;
+ }
+ }
+ cursor(0);
+
+ return choice;
+}
+
+/* TODO: rewrite in asm. Maybe. */
+unsigned long get_num(int maxlen)
+{
+ /* see comment in fancy_numbers for why this is static */
+ static char number[20];
+
+ int input,
+ character = 0;
+
+ long amount;
+
+ putchar(' ');
+ cursor(1);
+ putchar(BKSP);
+ while ((input = getch()) != '\n')
+ {
+ if (((input == BKSP) || (input == 127)) && (character == 0))
+ {
+ } else if ((input == BKSP) || (input == 127)) {
+ putchar(BKSP);
+ number[character] = '\0';
+ character--;
+ } else if (character >= maxlen) {
+ } else if (input == '\33') {
+ flushinp();
+ } else if (((input == 'A') || (input == 'a')) &&
+ (character == 0) && (maxlen > 1)) {
+ putchar(input);
+ number[character] = input;
+ character++;
+ } else if ((input < 48) || (input > 57)) {
+ } else {
+ putchar(input);
+ number[character] = input;
+ character++;
+ }
+ }
+
+ number[character] = '\0';
+ if ((strcmp(number, "A") == 0) || (strcmp(number, "a") == 0))
+ {
+ amount = -1;
+ } else {
+ amount = strtol(number, (char **)NULL, 10);
+ }
+
+ cursor(0);
+ return amount;
+}
+
+/* TODO: rewrite in asm */
+void cash_or_guns(void)
+{
+ int choice = 0;
+
+ clrscr();
+ cputs("Do you want to start . . .\r\n\r\n");
+ cputs(" 1) With cash (and a debt)\r\n\r\n");
+ cputs(" >> or <<\r\n\r\n");
+ cputs(" 2) With five guns and no cash\r\n");
+ cputs(" (But no debt!)\r\n");
+
+ while ((choice != '1') && (choice != '2'))
+ {
+ gotoxy(10, 10);
+ cursor(1);
+ cputc('?');
+ choice = get_one();
+ cursor(0);
+ }
+
+ cputc(choice);
+ if (choice == '1')
+ {
+ cash = 400;
+ debt = 5000;
+ hold = 60;
+ guns = 0;
+ li = 0;
+ bp = 10;
+ } else {
+ cash = 0;
+ debt = 0;
+ hold = 10;
+ guns = 5;
+ li = 1;
+ bp = 7;
+ }
+
+ return;
+}
+
+void set_prices(void)
+{
+ price[0] = base_price[0][port] / 2 * (randi()%3 + 1) * base_price[0][0];
+ price[1] = base_price[1][port] / 2 * (randi()%3 + 1) * base_price[1][0];
+ price[2] = base_price[2][port] / 2 * (randi()%3 + 1) * base_price[2][0];
+ price[3] = base_price[3][port] / 2 * (randi()%3 + 1) * base_price[3][0];
+ return;
+}
+
+
+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");
+
+ show_damage();
+ 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 ");
+ 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));
+ 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);
+ cprintulong(hold);
+ } else {
+ revers(1);
+ cputs("Overload");
+ revers(0);
+ }
+
+ cputsxy(16, 8, "Guns ");
+ // printw("%d", guns);
+ cprintulong(guns);
+
+ cputsxy(4, 9, "Opium ");
+ // printw("%d", hold_[0]);
+ cprintulong(hold_[0]);
+
+ cputsxy(4, 10, "Silk ");
+ // printw("%d", hold_[1]);
+ cprintulong(hold_[1]);
+
+ cputsxy(4, 11, "Arms ");
+ // printw("%d", hold_[2]);
+ cprintulong(hold_[2]);
+
+ cputsxy(4, 12, "General ");
+ // printw("%d", hold_[3]);
+ cprintulong(hold_[3]);
+
+ cputsxy(32, 2, "Date");
+ cputsxy(29, 3, "15 ");
+ 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) {
+ revers(1);
+ }
+ cputs(st[i]);
+ cputc(':');
+ cprintulong(status);
+ revers(0);
+
+ cputsxy(0, 14, "Cash: ");
+ fancy_numbers(cash, fancy_num);
+ cputs(fancy_num);
+ cputsxy(20, 14, "Bank: ");
+ fancy_numbers(bank, fancy_num);
+ cputs(fancy_num);
+}
+
+/* Unlike the Linux port, splash_intro() doesn't have to draw
+ the "programmed by" etc. text in the intro screen, as it's
+ preloaded into screen memory as a xex segment... but it
+ means splash_intro() can *only* be called by main(), once,
+ at program startup. So we don't get a 2nd splash intro
+ when answering Y to 'Play Again?".
+ Ideally, I should redefine enough graphics characters
+ that I can draw a nice ATASCII trading ship. But for
+ now I'll just draw 6 of the lorchas.
+ */
+void splash_intro(void)
+{
+ int i;
+
+ for(i=0; i<3; i++) draw_lorcha(i, 0, 0);
+ for(i=5; i<8; i++) draw_lorcha(i, 0, 0);
+
+ while(!kbhit())
+ ;
+
+ // for(i=0; i<3; i++) sink_lorcha(i);
+ // for(i=5; i<8; i++) sink_lorcha(i);
+
+ flushinp();
+ return;
+}
+
+void mchenry(void)
+{
+ int 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("Will ye be wanting repairs? ");
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ // int percent = ((float) damage / capacity) * 100,
+ // this is likely wrong:
+ int percent = ((damage * 100) / (capacity * 100)) * 100,
+ time = ((year - 1860) * 12) + month;
+
+ /*
+ long br = ((((60 * (time + 3) / 4) * (float) randi() / RAND_MAX) +
+ 25 * (time + 3) / 4) * capacity / 50),
+ repair_price = (br * damage) + 1,
+ amount;
+ */
+
+ long br, repair_price, amount;
+ br = ((randclamp(60 * (time + 3) / 4) + 25 * (time + 3) / 4) * capacity / 50);
+ repair_price = (br * damage) + 1;
+
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Och, 'tis a pity to be ");
+ cprintulong(percent);
+ cputs("% damaged.\r\nWe can fix yer whole ship for ");
+ cprintulong(repair_price);
+ cputs(",\r\nor make partial repairs if you wish.\r\n");
+ cputs("How much will ye spend? ");
+
+ for (;;) {
+ gotoxy(24, 21);
+ amount = get_num(9);
+ if(amount == -1) {
+ if(repair_price > cash)
+ amount = repair_price;
+ else
+ amount = cash;
+ }
+ if(amount <= cash) {
+ cash -= amount;
+ // damage -= (int)((amount / br) + .5);
+ damage -= (int)(amount / br);
+ damage = (damage < 0) ? 0 : damage;
+ port_stats();
+ break;
+ }
+ }
+ }
+
+ return;
+}
+
+void retire(void)
+{
+ compradores_report();
+ revers(1);
+ cputs(" \r\n");
+ cputs(" Y o u ' r e a \r\n");
+ cputs(" \r\n");
+ cputs(" M I L L I O N A I R E ! \r\n");
+ cputs(" \r\n");
+ revers(1);
+ timeout(5000);
+ getch();
+ timeout(-1);
+
+ final_stats();
+}
+
+void final_stats(void)
+{
+ int years = year - 1860,
+ time = ((year - 1860) * 12) + month,
+ choice = 0;
+
+ clrscr();
+ cputs("Your final status:\r\n\r\n");
+ cash = cash + bank - debt;
+ fancy_numbers(cash, fancy_num);
+ cputs("Net cash: ");
+ cputs(fancy_num);
+ cputs("\r\nShip size: ");
+ cprintulong(capacity);
+ cputs(" units with ");
+ cprintulong(guns);
+ cputs(" guns\r\n\r\n");
+ cputs("You traded for ");
+ cprintulong(years);
+ cputs(" year");
+ if (years != 1)
+ {
+ cputc('s');
+ }
+ cputs(" and ");
+ cprintulong(month);
+ cputs(" month");
+ if (month > 1)
+ {
+ cputc('s');
+ }
+ cputs("\r\n\r\n");
+ cash = cash / 100 / time;
+ revers(1);
+ cputs("Your score is ");
+ cprintulong(cash);
+ cputs(".\r\n");
+ revers(0);
+ if ((cash < 100) && (cash >= 0))
+ {
+ cputs("Have you considered a land based job?\r\n\r\n\r\n");
+ } else if (cash < 0) {
+ cputs("The crew has requested that you stay on\r\n");
+ cputs("shore for their safety!!\r\n\r\n");
+ } else {
+ cputs("\r\n\r\n\r\n");
+ }
+ cputs("Your Rating:\r\n");
+ cputs(" _______________________________\r\n");
+ cputs("|");
+ if (cash > 49999)
+ {
+ revers(1);
+ }
+ cputs("Ma Tsu");
+ revers(0);
+ cputs(" 50,000 and over |\r\n");
+ cputs("|");
+ if ((cash < 50000) && (cash > 7999))
+ {
+ revers(1);
+ }
+ cputs("Master Taipan");
+ revers(0);
+ cputs(" 8,000 to 49,999|\r\n");
+ cputs("|");
+ if ((cash < 8000) && (cash > 999))
+ {
+ revers(1);
+ }
+ cputs("Taipan");
+ revers(0);
+ cputs(" 1,000 to 7,999|\r\n");
+ cputs("|");
+ if ((cash < 1000) && (cash > 499))
+ {
+ revers(1);
+ }
+ cputs("Compradore");
+ revers(0);
+ cputs(" 500 to 999|\r\n");
+ cputs("|");
+ if (cash < 500)
+ {
+ revers(1);
+ }
+ cputs("Galley Hand");
+ revers(0);
+ cputs(" less than 500|\r\n");
+ cputs("|_______________________________|\r\n\r\n");
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ gotoxy(0, 22);
+ cputs("Play again? ");
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ bank = 0;
+ hkw_[0] = 0;
+ hkw_[1] = 0;
+ hkw_[3] = 0;
+ hkw_[4] = 0;
+ hold_[0] = 0;
+ hold_[1] = 0;
+ hold_[2] = 0;
+ hold_[3] = 0;
+ hold = 0;
+ capacity = 60;
+ damage = 0;
+ month = 1;
+ year = 1860;
+ port = 1;
+
+ // splash_intro();
+ name_firm();
+ cash_or_guns();
+ set_prices();
+
+ return;
+ }
+
+ clrscr();
+
+ exit(0);
+}
+
+void transfer(void)
+{
+ int i, in_use;
+
+ long amount = 0;
+
+ if ((hkw_[0] == 0) && (hold_[0] == 0) &&
+ (hkw_[1] == 0) && (hold_[1] == 0) &&
+ (hkw_[2] == 0) && (hold_[2] == 0) &&
+ (hkw_[3] == 0) && (hold_[3] == 0))
+ {
+ gotoxy(0, 22);
+ clrtobot();
+ cputs("You have no cargo, Taipan.\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ return;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ if (hold_[i] > 0)
+ {
+ for (;;)
+ {
+ compradores_report();
+ cputs("How much ");
+ cputs(item[i]);
+ cputs(" shall I move\r\nto the warehouse, Taipan? ");
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = hold_[i];
+ }
+ if (amount <= hold_[i])
+ {
+ in_use = hkw_[0] + hkw_[1] + hkw_[2] + hkw_[3];
+ if ((in_use + amount) <= 10000)
+ {
+ hold_[i] -= amount;
+ hkw_[i] += amount;
+ hold += amount;
+ break;
+ } else if (in_use == 10000) {
+ gotoxy(0, 21);
+ cputs("Your warehouse is full, Taipan!");
+ } else {
+ gotoxy(0, 21);
+ cputs("Your warehouse will only hold an\r\nadditional ");
+ cprintulong(10000 - in_use);
+ cputs("%d, Taipan!");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ } else {
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("You have only ");
+ cprintulong(hold_[i]);
+ cputs(", Taipan.\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ port_stats();
+ }
+
+ if (hkw_[i] > 0)
+ {
+ for (;;)
+ {
+ compradores_report();
+ cputs("How much ");
+ cputs(item[i]);
+ cputs("shall I move\r\naboard ship, Taipan? ");
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = hkw_[i];
+ }
+ if (amount <= hkw_[i])
+ {
+ hold_[i] += amount;
+ hkw_[i] -= amount;
+ hold -= amount;
+ break;
+ } else {
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("You have only ");
+ cprintulong(hkw_[i]);
+ cputs(", Taipan.\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ port_stats();
+ }
+ }
+
+ return;
+}
+
+void quit(void)
+{
+ int choice = 0,
+ result = 0;
+
+ compradores_report();
+ cputs("Taipan, do you wish me to go to:\r\n");
+ cputs("1) Hong Kong, 2) Shanghai, 3) Nagasaki,\r\n");
+ cputs("4) Saigon, 5) Manila, 6) Singapore, or\r\n");
+ cputs("7) Batavia ? ");
+
+ for (;;)
+ {
+ gotoxy(13, 21);
+ clrtobot();
+
+ choice = get_num(1);
+
+ if (choice == port)
+ {
+ cputs("\r\n\nYou're already here, Taipan.");
+ timeout(5000);
+ getch();
+ timeout(-1);
+ } else if ((choice >= 1) && (choice <= 7)) {
+ port = choice;
+ break;
+ }
+ }
+
+ at_sea();
+ captains_report();
+
+#ifdef COMBAT_TEST
+ if(1)
+#else
+ if (randi()%bp == 0)
+#endif
+ {
+ int num_ships = randi()%((capacity / 10) + guns) + 1;
+
+ if (num_ships > 9999)
+ {
+ num_ships = 9999;
+ }
+ cprintulong(num_ships);
+ cputs(" hostile ships approaching, Taipan!\r\n");
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ result = sea_battle(GENERIC, num_ships);
+ }
+
+ if (result == 2)
+ {
+ port_stats();
+ at_sea();
+
+ captains_report();
+ cputs("Li Yuen's fleet drove them off!");
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+ }
+
+ if (((result == 0) && (randi()%(4 + (8 * li))) == 0) || (result == 2))
+ {
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Li Yuen's pirates, Taipan!!\r\n\n");
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ if (li > 0)
+ {
+ cputs("Good joss!! They let us be!!\r\n");
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ return;
+ } else {
+ int num_ships = randi()%((capacity / 5) + guns) + 5;
+
+ cprintulong(num_ships);
+ cputs("ships of Li Yuen's pirate\r\n");
+ cputs("fleet, Taipan!!\r\n");
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ sea_battle(LI_YUEN, num_ships);
+ }
+ }
+
+ if (result > 0)
+ {
+ port_stats();
+ at_sea();
+
+ captains_report();
+ if (result == 1)
+ {
+ fancy_numbers(booty, fancy_num);
+ cputs("We captured some booty.\r\n");
+ cputs("It's worth ");
+ cputs(fancy_num);
+ cputc('!');
+ cash += booty;
+ } else if (result == 3) {
+ cputs("We made it!");
+ } else {
+ cputs("The buggers got us, Taipan!!!\r\n");
+ cputs("It's all over, now!!!");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+
+ final_stats();
+ return;
+ }
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+ }
+
+ if (randi()%10 == 0)
+ {
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Storm, Taipan!!\r\n\n");
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ if (randi()%30 == 0)
+ {
+ cputs(" I think we're going down!!\r\n\n");
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ // if (((damage / capacity * 3) * ((float) randi() / RAND_MAX)) >= 1)
+ if(randclamp(damage / capacity * 3) >= 1)
+ {
+ cputs("We're going down, Taipan!!\r\n");
+ timeout(5000);
+ getch();
+ timeout(-1);
+
+ final_stats();
+ }
+ }
+
+ cputs(" We made it!!\r\n\n");
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ if (randi()%3 == 0)
+ {
+ int orig = port;
+
+ while (port == orig)
+ {
+ port = randi()%7 + 1;
+ }
+
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("We've been blown off course\r\nto ");
+ cputs(location[port]);
+ timeout(3000);
+ getch();
+ timeout(-1);
+ }
+ }
+
+ month++;
+ if (month == 13)
+ {
+ month = 1;
+ year++;
+ ec += 10;
+ ed += 1;
+ }
+
+ /* debt calculation original formula was:
+
+ debt = debt + (debt * .1);
+
+ int-based formula is the same, except it would never
+ increase if debt is <= 10, so we fudge it with debt++
+ in that case. Which means small debts accrue interest
+ *much* faster, but that shouldn't affect gameplay much.
+ There needs to be some overflow detection though... or
+ maybe we let the overflow through, and the player can
+ think of it as Wu forgiving the debt after enough years
+ go by (or, he lost the paperwork?). Most likely though,
+ the player gets his throat cut long before the amount
+ overflows.
+
+ */
+
+ if(debt) {
+ if(debt > 10)
+ debt += (debt / 10);
+ else
+ debt++;
+ }
+
+ /* bank calculation original formula was:
+ bank = bank + (bank * .005);
+ int-based formula is the same, except when bank <= 200,
+ it's linear.
+ */
+ if(bank) {
+ if(bank > 200)
+ bank += (bank / 200);
+ else
+ bank++;
+ }
+
+ set_prices();
+
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Arriving at ");
+ cputs(location[port]);
+ cputs("...");
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ return;
+}
+
+void li_yuen_extortion(void)
+{
+ int time = ((year - 1860) * 12) + month,
+ choice = 0;
+
+ /*
+ float i = 1.8,
+ j = 0,
+ amount = 0;
+ */
+ unsigned long amount = 0;
+ unsigned int i = 2, j = 0;
+
+ if (time > 12)
+ {
+ j = randi()%(1000 * time) + (1000 * time);
+ i = 1;
+ }
+
+ // amount = ((cash / i) * ((float) randi() / RAND_MAX)) + j;
+ amount = randclamp((cash >> (i - 1))) + j;
+
+ fancy_numbers(amount, fancy_num);
+
+ compradores_report();
+ cputs("Li Yuen asks ");
+ cputs(fancy_num);
+ cputs(" in donation\r\nto the temple of Tin Hau, the Sea\r\n");
+
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ gotoxy(0, 20);
+ cputs("Goddess. Will you pay? ");
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ if (amount <= cash)
+ {
+ cash -= amount;
+ li = 1;
+ } else {
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Taipan, you do not have enough cash!!\r\n\r\n");
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ cputs("Do you want Elder Brother Wu to make up\r\n");
+ cputs("the difference for you? ");
+ choice = 0;
+ while ((choice != 'Y') && (choice != 'y') &&
+ (choice != 'N') && (choice != 'n'))
+ {
+ choice = get_one();
+ }
+
+ if ((choice == 'Y') || (choice == 'y'))
+ {
+ amount -= cash;
+ debt += amount;
+ cash = 0;
+ li = 1;
+
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Elder Brother has given Li Yuen the\r\n");
+ cputs("difference between what he wanted and\r\n");
+ cputs("your cash on hand and added the same\r\n");
+ cputs("amount to your debt.\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ } else {
+ cash = 0;
+
+ cputs("Very well. Elder Brother Wu will not pay\r\n");
+ cputs("Li Yuen the difference. I would be very\r\n");
+ cputs("wary of pirates if I were you, Taipan.\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ }
+
+ port_stats();
+
+ return;
+}
+
+void elder_brother_wu(void)
+{
+ int choice = 0;
+
+ long wu = 0;
+
+ compradores_report();
+ cputs("Do you have business with Elder Brother\r\n");
+ cputs("Wu, the moneylender? ");
+
+ for (;;)
+ {
+ gotoxy(21, 19);
+
+ choice = get_one();
+ if ((choice == 'N') || (choice == 'n') || choice == 0)
+ {
+ break;
+ } else if ((choice == 'Y') || (choice == 'y')) {
+ if (((int)cash == 0) && ((int)bank == 0) && (guns == 0) &&
+ (hold_[0] == 0) && (hkw_[0] == 0) &&
+ (hold_[1] == 0) && (hkw_[1] == 0) &&
+ (hold_[2] == 0) && (hkw_[2] == 0) &&
+ (hold_[3] == 0) && (hkw_[3] == 0))
+ {
+ int i = randi()%1500 + 500,
+ j;
+
+ wu_bailout++;
+ j = randi()%2000 * wu_bailout + 1500;
+
+ for (;;)
+ {
+ compradores_report();
+ cputs("Elder Brother is aware of your plight,\r\n");
+ cputs("Taipan. He is willing to loan you an\r\n");
+ cputs("additional ");
+ cprintulong(i);
+ cputs(" if you will pay back\r\n");
+ cprintulong(j);
+ cputs(". Are you willing, Taipan? ");
+
+ choice = get_one();
+ if ((choice == 'N') || (choice == 'n'))
+ {
+ compradores_report();
+ cputs("Very well, Taipan, the game is over!\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+
+ final_stats();
+ } else if ((choice == 'Y') || (choice == 'y')) {
+ cash += i;
+ debt += j;
+ port_stats();
+
+ compradores_report();
+ cputs("Very well, Taipan. Good joss!!\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+
+ return;
+ }
+ }
+ } else if ((cash > 0) && (debt != 0)) {
+ for (;;)
+ {
+ compradores_report();
+ cputs("How much do you wish to repay\r\n");
+ cputs("him? ");
+
+ wu = get_num(9);
+ if (wu == -1)
+ {
+ wu = cash;
+ }
+ if (wu <= cash)
+ {
+ if(wu > debt) wu = debt;
+ cash -= wu;
+ debt -= wu;
+ /* // currently debt is unsigned so the negative debt
+ // bug (or feature) is unimplemented.
+ if ((wu > debt) && (debt > 0))
+ {
+ debt -= (wu + 1);
+ } else {
+ debt -= wu;
+ }
+ */
+ break;
+ } else {
+ gotoxy(0, 18);
+ clrtobot();
+ fancy_numbers(cash, fancy_num);
+ cputs("Taipan, you only have ");
+ cputs(fancy_num);
+ cputs("\r\nin cash.\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ }
+ port_stats();
+
+ for (;;)
+ {
+ compradores_report();
+ cputs("How much do you wish to\r\n");
+ cputs("borrow? ");
+
+ wu = get_num(9);
+ if (wu == -1)
+ {
+ wu = (cash * 2);
+ }
+ if (wu <= (cash * 2))
+ {
+ cash += wu;
+ debt += wu;
+ break;
+ } else {
+ cputs("\r\n\r\nHe won't loan you so much, Taipan!");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ port_stats();
+
+ break;
+ }
+ }
+
+ if ((debt > 20000) && (cash > 0) && (randi()%5 == 0))
+ {
+ int num = randi()%3 + 1;
+
+ cash = 0;
+ port_stats();
+
+ compradores_report();
+ cputs("Bad joss!!\r\n");
+ cprintulong(num);
+ cputs(" of your bodyguards have been killed\r\n");
+ cputs("by cutthroats and you have been robbed\r\n");
+ cputs("of all of your cash, Taipan!!\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+
+ return;
+}
+
+void good_prices(void)
+{
+ /* see comment in fancy_numbers for why this is static */
+ static char item[14];
+
+ int i = randi()%4,
+ j = randi()%2;
+
+ if (i == 0)
+ {
+ strcpy(item, "Opium");
+ } else if (i == 1) {
+ strcpy(item, "Silk");
+ } else if (i == 2) {
+ strcpy(item, "Arms");
+ } else {
+ strcpy(item, "General Cargo");
+ }
+
+ compradores_report();
+ cputs("Taipan!! The price of ");
+ cputs(item);
+ cputs("\r\n has ");
+ if (j == 0)
+ {
+ price[i] = price[i] / 5;
+ cputs("dropped");
+ } else {
+ price[i] = price[i] * (randi()%5 + 5);
+ cputs("risen");
+ }
+ cputs(" to ");
+ cprintulong(price[i]);
+ cputs("!!\r\n");
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+}
+
+int port_choices(void)
+{
+ int choice = 0;
+
+ compradores_report();
+ cputs("Taipan, present prices per unit here are"); /* NB: exactly 40 cols */
+ cputs(" Opium: Silk:\r\n");
+ cputs(" Arms: General:\r\n");
+ gotoxy(11, 19);
+ cprintulong(price[0]);
+ gotoxy(29, 19);
+ cprintulong(price[1]);
+ gotoxy(11, 20);
+ cprintulong(price[2]);
+ gotoxy(29, 20);
+ cprintulong(price[3]);
+
+ for (;;)
+ {
+ gotoxy(0, 22);
+ clrtobot();
+
+ cursor(1);
+ if (port == 1)
+ {
+ if ((cash + bank) >= 1000000)
+ {
+ cputs("Shall I Buy, Sell, Visit bank, Transfer\r\n");
+ cputs("cargo, Quit trading, or Retire? ");
+
+ choice = cgetc();
+ if ((choice == 'B') || (choice == 'b') ||
+ (choice == 'S') || (choice == 's') ||
+ (choice == 'V') || (choice == 'v') ||
+ (choice == 'T') || (choice == 't') ||
+ (choice == 'Q') || (choice == 'q') ||
+ (choice == 'R') || (choice == 'r'))
+ {
+ break;
+ }
+ } else {
+ cputs("Shall I Buy, Sell, Visit bank, Transfer\r\n");
+ cputs("cargo, or Quit trading? ");
+
+ choice = cgetc();
+ if ((choice == 'B') || (choice == 'b') ||
+ (choice == 'S') || (choice == 's') ||
+ (choice == 'V') || (choice == 'v') ||
+ (choice == 'T') || (choice == 't') ||
+ (choice == 'Q') || (choice == 'q'))
+ {
+ break;
+ }
+ }
+ } else {
+ cputs("Shall I Buy, Sell, or Quit trading? ");
+
+ choice = cgetc();
+ if ((choice == 'B') || (choice == 'b') ||
+ (choice == 'S') || (choice == 's') ||
+ (choice == 'Q') || (choice == 'q'))
+ {
+ break;
+ }
+ }
+ cursor(1);
+ }
+
+ return choice;
+}
+
+
+/* TODO: rewrite in asm, or at least better C */
+void name_firm(void)
+{
+ int input,
+ character = 0;
+
+ clrscr();
+
+ chlinexy(1, 7, 38);
+ chlinexy(1, 16, 38);
+ cvlinexy(0, 8, 8);
+ cvlinexy(39, 8, 8);
+ cputcxy(0, 7, 17); // upper left corner
+ cputcxy(0, 16, 26); // lower left corner
+ cputcxy(39, 7, 5); // upper right corner
+ cputcxy(39, 16, 3); // lower right corner
+
+ gotoxy(6, 9);
+ cputs("Taipan,");
+ gotoxy(2, 11);
+ cputs("What will you name your");
+ gotoxy(6, 13);
+ cursor(1);
+ cputs("Firm:");
+ chlinexy(12, 14, 22);
+
+ gotoxy(12, 13);
+
+ while (((input = getch()) != ENTER) && (character < 22))
+ {
+ if (((input == BKSP) || (input == 127)) && (character == 0))
+ {
+ // nop
+ } else if ((input == BKSP) || (input == 127)) {
+ gotox(12 + character - 1);
+ cputc(' ');
+ gotox(12 + character - 1);
+ firm[character] = '\0';
+ character--;
+ } else if (input == '\33') {
+ flushinp();
+ } else {
+ cputc(input);
+ firm[character] = input;
+ character++;
+ }
+ }
+
+ cursor(0);
+ firm[character] = '\0';
+
+ return;
+}
+
+void buy(void)
+{
+ /* see comment in fancy_numbers for why this is static */
+ // static char space[5];
+
+ int choice = 0;
+
+ long afford,
+ amount;
+
+ for (;;)
+ {
+ gotoxy(0, 22);
+ clrtobot();
+
+ cputs("What do you wish me to buy, Taipan? ");
+
+ /* TODO: buy() sell() and throwing cargo, common code in get_item() */
+ choice = lc(get_one());
+ if(choice == 'o') {
+ choice = 0;
+ break;
+ } else if (choice == 's') {
+ choice = 1;
+ break;
+ } else if (choice == 'a') {
+ choice = 2;
+ break;
+ } else if (choice == 'g') {
+ choice = 3;
+ break;
+ }
+ }
+
+ for (;;)
+ {
+ gotoxy(31, 21);
+ clrtobot();
+
+ afford = cash / price[choice];
+ revers(1);
+ cputs(" You can ");
+ revers(0);
+ gotoxy(0, 22);
+ cputs("How much ");
+ cputs(item[choice]);
+ cputs(" shall");
+ gotoxy(31, 22);
+ revers(1);
+ cputs(" afford ");
+ gotoxy(31, 23);
+ cputs(" ");
+ gotoxy(31, 23);
+
+ /* TODO: is this really right? */
+ if(afford < 100) cputc(' ');
+ if(afford < 10000) cputc(' ');
+ if(afford < 1000000) cputc(' ');
+ if(afford < 100000000) cputc(' ');
+
+ /*
+ if (afford < 100)
+ {
+ strcpy(space, " ");
+ } else if (afford < 10000) {
+ strcpy(space, " ");
+ } else if (afford < 1000000) {
+ strcpy(space, " ");
+ } else if (afford < 100000000) {
+ strcpy(space, " ");
+ } else {
+ strcpy(space, "");
+ }
+ cputs(space);
+ */
+
+ cprintulong(afford);
+ revers(0);
+
+ gotoxy(0, 23);
+ cputs("I buy, Taipan: ");
+
+ amount = get_num(9);
+ if(amount == -1) {
+ amount = afford;
+ }
+ if(amount <= afford) {
+ break;
+ }
+ }
+
+ cash -= (amount * price[choice]);
+ hold_[choice] += amount;
+ hold -= amount;
+
+ return;
+}
+
+void sell(void) {
+ int choice = 0;
+
+ long amount;
+
+ for (;;)
+ {
+ gotoxy(0, 22);
+ clrtobot();
+
+ cputs("What do you wish me to sell, Taipan? ");
+
+ /* TODO: buy() sell() and throwing cargo, common code in get_item() */
+ choice = lc(get_one());
+ if(choice == 'o') {
+ choice = 0;
+ break;
+ } else if(choice == 's') {
+ choice = 1;
+ break;
+ } else if(choice == 'a') {
+ choice = 2;
+ break;
+ } else if(choice == 'g') {
+ choice = 3;
+ break;
+ }
+ }
+
+ for (;;)
+ {
+ gotoxy(0, 22);
+ clrtobot();
+
+ cputs("How much ");
+ cputs(item[choice]);
+ cputs(" shall\r\n");
+ cputs("I sell, Taipan: ");
+
+ amount = get_num(9);
+
+ if (amount == -1)
+ {
+ amount = hold_[choice];
+ }
+ if (hold_[choice] >= amount)
+ {
+ hold_[choice] -= amount;
+ break;
+ }
+ }
+
+ cash += (amount * price[choice]);
+ hold += amount;
+
+ return;
+}
+
+void visit_bank(void)
+{
+ long amount = 0;
+
+ for (;;)
+ {
+ compradores_report();
+ cputs("How much will you deposit? ");
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = cash;
+ }
+ if (amount <= cash)
+ {
+ cash -= amount;
+ bank += amount;
+ break;
+ } else {
+ gotoxy(0, 18);
+ clrtobot();
+ fancy_numbers(cash, fancy_num);
+ cputs("Taipan, you only have ");
+ cputs(fancy_num);
+ cputs("\r\nin cash.\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ port_stats();
+
+ for (;;)
+ {
+ compradores_report();
+ cputs("How much will you withdraw? ");
+
+ amount = get_num(9);
+ if (amount == -1)
+ {
+ amount = bank;
+ }
+ if (amount <= bank)
+ {
+ cash += amount;
+ bank -= amount;
+ break;
+ } else {
+ fancy_numbers(cash, fancy_num);
+ cputs("Taipan, you only have ");
+ cputs(fancy_num);
+ cputs("\r\nin the bank.");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+ }
+ port_stats();
+
+ return;
+}
+
+/*
+void debttest() {
+ int i;
+
+ debt = 1;
+
+ for(i=0; i<20; i++) {
+ debt = debt + (debt >> 8) + (debt >> 10);
+ // debt = debt + (debt >> 4) + (debt >> 5) + (debt >> 7) - (debt >> 9); // debt *= 0.09961
+ printf("%lu\n", debt);
+ }
+
+ cgetc();
+ clrscr();
+ debt = 1;
+
+ for(i=0; i<20; i++) {
+ if(debt > 200)
+ debt += (debt / 200);
+ else
+ debt++;
+
+ printf("%lu\n", debt);
+ }
+ cgetc();
+
+}
+*/
+
+/* N.B. cc65 is perfectly OK with main(void), and it avoids
+ warnings about argv/argc unused. */
+int main(void) {
+ int choice;
+
+ /*
+ {
+ int status;
+ capacity = 60;
+ damage = 47;
+ status = 100 - ((damage * 100) / capacity);
+ cprintulong(status);
+hang: goto hang;
+ }
+ */
+
+ /*
+ _randomize();
+ while(1) {
+ clrscr();
+ cprintulong(randi());
+ cputs("\r\n");
+ cprintulong(rand());
+ cgetc();
+ }
+ */
+
+ // fancytest();
+ // debttest();
+ atari_text_setup();
+ initrand();
+ splash_intro();
+ name_firm();
+ cash_or_guns();
+ set_prices();
+
+ for (;;)
+ {
+ choice = 0;
+
+ port_stats();
+
+ if ((port == 1) && (li == 0) && (cash > 0))
+ {
+ li_yuen_extortion();
+ }
+
+ if ((port == 1) && (damage > 0))
+ {
+ mchenry();
+ }
+
+ if ((port == 1) && (debt >= 10000) && (wu_warn == 0))
+ {
+ int braves = randi()%100 + 50;
+
+ compradores_report();
+ cputs("Elder Brother Wu has sent ");
+ cprintulong(braves);
+ cputs(" braves\r\n");
+ cputs("to escort you to the Wu mansion, Taipan.\r\n");
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("Elder Brother Wu reminds you of the\r\n");
+ cputs("Confucian ideal of personal worthiness,\r\n");
+ cputs("and how this applies to paying one's\r\n");
+ cputs("debts.\r\n");
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+
+ gotoxy(0, 18);
+ clrtobot();
+ cputs("He is reminded of a fabled barbarian\r\n");
+ cputs("who came to a bad end, after not caring\r\n");
+ cputs("for his obligations.\r\n\r\n");
+ cputs("He hopes no such fate awaits you, his\r\n");
+ cputs("friend, Taipan.\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+
+ wu_warn = 1;
+ }
+
+ if (port == 1)
+ {
+ elder_brother_wu();
+ }
+
+ if (randi()%4 == 0)
+ {
+ if (randi()%2 == 0)
+ {
+ new_ship();
+ } else if (guns < 1000) {
+ new_gun();
+ }
+ }
+
+ if ((port != 1) && (randi()%18 == 0) && (hold_[0] > 0))
+ {
+ // float fine = ((cash / 1.8) * ((float) randi() / RAND_MAX)) + 1;
+ // the 1.8 is now a 2
+ unsigned long fine = randclamp(cash >> 1) + 1;
+
+ hold += hold_[0];
+ hold_[0] = 0;
+ cash -= fine;
+
+ port_stats();
+
+ fancy_numbers(fine, fancy_num);
+ compradores_report();
+ cputs("Bad Joss!!\r\n");
+ cputs("The local authorities have seized your\r\n");
+ cputs("Opium cargo and have also fined you\r\n");
+ cputs(fancy_num);
+ cputs(", Taipan!\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+
+ if ((randi()%50 == 0) &&
+ ((hkw_[0] + hkw_[1] + hkw_[2] + hkw_[3]) > 0))
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ // hkw_[i] = ((hkw_[i] / 1.8) * ((float) randi() / RAND_MAX));
+ // the 1.8 is now a 2
+ hkw_[i] = randclamp(hkw_[i] >> 1);
+ }
+
+ port_stats();
+
+ compradores_report();
+ cputs("Messenger reports large theft\r\n");
+ cputs("from warehouse, Taipan.\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+
+ if (randi()%20 == 0)
+ {
+ if (li > 0) { li++; }
+ if (li == 4) { li = 0; }
+ }
+
+ if ((port != 1) && (li == 0) && (randi()%4 != 0))
+ {
+ compradores_report();
+ cputs("Li Yuen has sent a Lieutenant,\r\n");
+ cputs("Taipan. He says his admiral wishes\r\n");
+ cputs("to see you in Hong Kong, posthaste!\r\n");
+
+ timeout(3000);
+ getch();
+ timeout(-1);
+ }
+
+ if (randi()%9 == 0)
+ {
+ good_prices();
+ }
+
+ if ((cash > 25000) && (randi()%20 == 0))
+ {
+ // float robbed = ((cash / 1.4) * ((float) randi() / RAND_MAX));
+ // line below changes the 1.4 to 1.5
+ unsigned long robbed = randclamp((cash >> 2) + (cash >> 1));
+
+ cash -= robbed;
+ port_stats();
+
+ fancy_numbers(robbed, fancy_num);
+ compradores_report();
+ cputs("Bad Joss!!\r\n");
+ cputs("You've been beaten up and\r\n");
+ cputs("robbed of ");
+ cputs(fancy_num);
+ cputs(" in cash, Taipan!!\r\n");
+
+ timeout(5000);
+ getch();
+ timeout(-1);
+ }
+
+ for (;;)
+ {
+ while ((choice != 'Q') && (choice != 'q'))
+ {
+ switch (choice = port_choices())
+ {
+ case 'B':
+ case 'b':
+ buy();
+ break;
+
+ case 'S':
+ case 's':
+ sell();
+ break;
+
+ case 'V':
+ case 'v':
+ visit_bank();
+ break;
+
+ case 'T':
+ case 't':
+ transfer();
+ break;
+
+ case 'R':
+ case 'r':
+ retire();
+ }
+
+ port_stats();
+ }
+
+ choice = 0;
+ if (hold >= 0)
+ {
+ quit();
+ break;
+ } else {
+ overload();
+ }
+ }
+ }
+
+ cgetc();
+ POKE(709, 0);
+hangmain:
+ goto hangmain;
+ return 0;
+}
diff --git a/taipan.dsk b/taipan.dsk
new file mode 100644
index 0000000..5736ca9
--- /dev/null
+++ b/taipan.dsk
Binary files differ
diff --git a/timed_getch.pl b/timed_getch.pl
new file mode 100644
index 0000000..d9f267e
--- /dev/null
+++ b/timed_getch.pl
@@ -0,0 +1,48 @@
+#!/usr/bin/perl -w
+
+# replace this:
+
+# timeout(5000);
+# getch();
+# timeout(-1);
+
+# with this:
+
+# timed_getch(83);
+
+# the 83 comes from int(5000/1000*60)
+
+# indentation levels must be preserved!
+
+while(<>) {
+ my $line = $_;
+ if(/^(\s+)timeout\s*\((\d+)/) {
+ #warn "found timeout($2) at $.\n";
+ my $indent = $1;
+ my $jiffies = int(($2 / 1000) * 60);
+
+ if($jiffies == 60) {
+ $jiffies = "TMOUT_1S";
+ } elsif($jiffies == 180) {
+ $jiffies = "TMOUT_3S";
+ } elsif($jiffies == 300) {
+ $jiffies = "TMOUT_5S";
+ } else {
+ warn "no TMOUT_* constant for $jiffies, line $.\n";
+ }
+
+ my $next = <>;
+ if($next =~ /getch\(\)/) {
+ print $indent . "timed_getch($jiffies);\n";
+ my $last = <>;
+ if($last !~ /timeout\(-1\)/) {
+ print $last;
+ }
+ } else {
+ print $line;
+ print $next;
+ }
+ } else {
+ print $line;
+ }
+}
diff --git a/timed_getch.s b/timed_getch.s
new file mode 100644
index 0000000..8675290
--- /dev/null
+++ b/timed_getch.s
@@ -0,0 +1,26 @@
+
+ .export _timed_getch, _set_jiffy_timer
+ .import _cgetc
+
+_set_jiffy_timer:
+ sei
+ sta 540
+ stx 541
+ cli
+ rts
+
+_timed_getch:
+ jsr _set_jiffy_timer
+wait4key:
+ lda 540
+ ora 541
+ beq done
+ ldx 764
+ inx
+ beq wait4key
+ jmp _cgetc
+
+done:
+ lda #$ff ; return -1
+ tax
+ rts
diff --git a/title.pl b/title.pl
new file mode 100644
index 0000000..2f402f9
--- /dev/null
+++ b/title.pl
@@ -0,0 +1,7 @@
+#!/usr/bin/perl -w
+
+use bytes;
+print chr($_) for (0xff, 0xff, 0x40, 0xbc, 0xff, 0xbf);
+undef $/;
+$_ = <>;
+print $_;