From 2300d2813a524cbfeabac794335e7abe99263df6 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Tue, 29 Dec 2015 23:10:50 -0500 Subject: initial commit --- taipan.c_before_timed_getch | 2877 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2877 insertions(+) create mode 100644 taipan.c_before_timed_getch (limited to 'taipan.c_before_timed_getch') 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 +#include +#include +#include +#include +#include + +/* 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; +} -- cgit v1.2.3