#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; }