aboutsummaryrefslogtreecommitdiff
path: root/taipan.c
diff options
context:
space:
mode:
Diffstat (limited to 'taipan.c')
-rw-r--r--taipan.c2706
1 files changed, 2706 insertions, 0 deletions
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;
+}