aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <yalhcru@gmail.com>2016-01-15 14:35:01 -0500
committerB. Watson <yalhcru@gmail.com>2016-01-15 14:35:01 -0500
commitad7bbde98916040e8b527068ead084d009c899d4 (patch)
tree235d55e35b06a4a38366e9310f859600ddee2ff8
parent06f2620ead18279afdd2501c3fef409252aa7ea0 (diff)
downloadtaipan-ad7bbde98916040e8b527068ead084d009c899d4.tar.gz
check for cash int overflow, WIP
-rw-r--r--bignum.h36
-rw-r--r--taipan.c124
2 files changed, 98 insertions, 62 deletions
diff --git a/bignum.h b/bignum.h
index 185d118..67ae902 100644
--- a/bignum.h
+++ b/bignum.h
@@ -24,6 +24,7 @@
#define bignum(x) char x[6]
#define bignump char *
+/****** constants ******/
/* zero */
#define BIG_0 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
@@ -41,17 +42,36 @@
/* max value for a ulong */
#define BIG_MAX_ULONG { 0x44, 0x42, 0x94, 0x96, 0x72, 0x95 }
+/****** functions ******/
+
+/* copy dest to src. could be a wrapper for memcpy() */
extern void __fastcall__ big_copy(bignump dest, bignump src);
+/* these 2 would be easy to implement, but aren't really needed */
// void int_to_big(int i, bignum *b);
// void uint_to_big(unsigned int i, bignum *b);
+/* convert an unsigned long to a bignum */
extern void __fastcall__ ulong_to_big(const unsigned long l, bignump b);
-/* returns 0 for success, nonzero for fail (overflow or negative) */
+/* convert a bignum to an unsigned long
+ returns 0 for success, nonzero for fail (overflow or negative) */
extern char __fastcall__ big_to_ulong(bignump b, unsigned long *l);
-// extern unsigned long __fastcall__ cformat_big(char *magnitude, const bignum *b);
+/* compare two bignums. like Perl's spaceship operator, <=>
+ returns | if
+ ---------+----------------
+ 0 | a == b
+ positive| a > b
+ negative| a < b
+
+BEWARE: unlike perl's <=>, the return value is *not* guaranteed to
+ be 0, 1, or -1. This is more like C's strcmp() or memcmp().
+ Do not depend on any particular positive or negative return
+ value from this:
+ if(big_cmp(a, b) == -1) // WRONG!
+ if(big_cmp(a, b) < 0) // Right. */
+extern signed char __fastcall__ big_cmp(bignump a, bignump b);
/* basic math functions. conceptually they return a boolean for
success, but only division has error checking.
@@ -74,19 +94,7 @@ extern char __cdecl__ big_div(bignump dest, bignump dividend, bignump divisor);
*/
extern char __fastcall__ bank_maxed_out(bignump b);
-/* comparison. Perl spaceship operator, <=>
- returns | if
- ---------+----------------
- 0 | a == b
- positive| a > b
- negative| a < b
-
-BEWARE: unlike perl's <=>, the return value is *not* guaranteed to
- be 0, 1, or -1. This is more like C's strcmp() or memcmp().
- */
// signed char big_cmp(const bignum *a, const bignum *b)
-extern signed char __fastcall__ big_cmp(bignump a, bignump b);
-
extern unsigned long cformat_big(char *magnitude, bignump b);
extern void cprintfancy_big(bignump b);
diff --git a/taipan.c b/taipan.c
index 96f6d84..fd471e8 100644
--- a/taipan.c
+++ b/taipan.c
@@ -5,6 +5,7 @@
#include <ctype.h>
#include <string.h> /* only for memcpy() */
#include <peekpoke.h>
+#include <stdint.h>
#include "sounds.h"
@@ -208,7 +209,6 @@ char wu_assassin = 0;
/* title screen now a separate xex segment (see Makefile for details) */
// void splash_intro(void);
-// int get_one(void);
#define get_one() agetc();
long get_num(void);
void name_firm(void);
@@ -227,7 +227,6 @@ 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);
void fight_stats(int ships, int orders);
void mchenry(void);
@@ -238,14 +237,12 @@ void you_only_have(unsigned char in_bank);
void cprintulong(unsigned long ul);
void cprintfancy_ctr(unsigned long num, unsigned char center);
#define cprintfancy(num) cprintfancy_ctr(num, 0)
+void too_much_cash(void);
+char would_overflow(unsigned long a, unsigned long b);
unsigned char firmpos;
-/*
-char firm[23],
- fancy_num[24];
- */
-
+/* use page 6 for these buffers */
char *firm = (char *) 0x680;
char *fancy_buf = (char *) 0x600;
@@ -310,6 +307,7 @@ long damage = 0, capacity = 60, newdamage;
bignum(big1M) = BIG_1M;
bignum(big100M) = BIG_100M;
bignum(big1B) = BIG_1B;
+bignum(big0) = BIG_0;
/*
Requires a bit of explanation. b's value will always be zero or
@@ -353,10 +351,8 @@ void cprintfancy_big(bignump b) {
cprintulong(l);
} else {
if(l > 100) {
- // cprintf("%lu ", l / 10L);
cprintulong(l / 10L);
} else {
- // cprintf("%lu.%lu ", l / 10L, l % 10L);
cprintulong(l / 10L);
cputc('.');
cprintulong(l % 10L);
@@ -423,7 +419,6 @@ void new_ship(void) {
int choice = 0,
time;
- // float amount;
unsigned long amount;
time = ((year - 1860) * 12) + month;
@@ -433,8 +428,6 @@ void new_ship(void) {
return;
}
- // fancy_numbers(amount, fancy_num);
-
compradores_report();
cputs("Do you wish to trade in your ");
if(damage > 0) {
@@ -446,7 +439,6 @@ void new_ship(void) {
}
cputs("\r\nship for one with 50 more capacity by\r\n");
cputs("paying an additional ");
- // cputs(fancy_num);
cprintfancy(amount);
cputs(", Taipan? ");
@@ -692,6 +684,9 @@ int sea_battle(int id, int num_ships) {
ik = 1;
booty = (time / 4 * 1000 * num_ships) + randi()%1000 + 250;
+ if(would_overflow(cash, booty)) {
+ booty = 0L;
+ }
for(i = 0; i <= 9; i++) {
ships_on_screen[i] = 0;
@@ -1577,24 +1572,46 @@ void retire(void)
void final_stats(void)
{
-#ifdef BIGNUM
-#else
- /* TODO: write cprintlong() to print signed value */
- long finalcash;
-
int years = year - 1860,
time = ((year - 1860) * 12) + month,
choice = 0;
+#ifdef BIGNUM
+ long score;
+ bignum(finalcash);
+ bignum(big_100) = BIG_100;
+ bignum(bigscore);
+ bignum(bigtmp);
+
+ ulong_to_big(cash, finalcash);
+ ulong_to_big(debt, bigtmp);
+ big_add(finalcash, finalcash, bank);
+ big_sub(finalcash, finalcash, bigtmp);
+
+ big_div(bigscore, finalcash, big_100);
+ ulong_to_big((unsigned long)time, bigtmp);
+ big_div(bigscore, bigscore, bigtmp);
+
+ if(big_cmp(bigscore, big1M) > 0)
+ score = 1000000L;
+ else
+ big_to_ulong(bigscore, (unsigned long*)&score);
+#else
+ /* TODO: write cprintlong() to print signed value */
+ long finalcash = cash + bank - debt;
+ long score = finalcash / 100 / time;
+#endif
+
port_stat_dirty = 1;
clrscr();
cputs("Your final status:\r\n\r\n");
- finalcash = cash + bank - debt;
- // fancy_numbers(finalcash, fancy_num);
cputs("Net cash: ");
- // cputs(fancy_num);
+#ifdef BIGNUM
+ cprintfancy_big(finalcash);
+#else
cprintfancy(finalcash);
+#endif
cputs("\r\nShip size: ");
cprintulong(capacity);
cputs(" units with ");
@@ -1615,16 +1632,19 @@ void final_stats(void)
cputc('s');
}
cputs("\r\n\r\n");
- finalcash = finalcash / 100 / time;
revers(1);
cputs("Your score is ");
- cprintulong(finalcash);
+#ifdef BIGNUM
+ cprintfancy_big(bigscore);
+#else
+ cprintulong(score);
cputs(".\r\n");
+#endif
revers(0);
- if ((finalcash < 100) && (finalcash >= 0))
+ if ((score < 100) && (score >= 0))
{
cputs("Have you considered a land based job?\r\n\r\n\r\n");
- } else if (finalcash < 0) {
+ } else if (score < 0) {
cputs("The crew has requested that you stay on\r\n");
cputs("shore for their safety!!\r\n\r\n");
} else {
@@ -1637,7 +1657,7 @@ void final_stats(void)
cputs("\r\n");
cputc('|');
- if (finalcash > 49999L)
+ if (score > 49999L)
{
revers(1);
}
@@ -1646,7 +1666,7 @@ void final_stats(void)
cputs(" 50,000 and over |\r\n");
cputc('|');
- if ((finalcash < 50000L) && (finalcash > 7999L))
+ if ((score < 50000L) && (score > 7999L))
{
revers(1);
}
@@ -1655,7 +1675,7 @@ void final_stats(void)
cputs(" 8,000 to 49,999|\r\n");
cputc('|');
- if ((finalcash < 8000L) && (finalcash > 999L))
+ if ((score < 8000L) && (score > 999L))
{
revers(1);
}
@@ -1664,7 +1684,7 @@ void final_stats(void)
cputs(" 1,000 to 7,999|\r\n");
cputc('|');
- if ((finalcash < 1000) && (finalcash > 499))
+ if ((score < 1000) && (score > 499))
{
revers(1);
}
@@ -1673,7 +1693,7 @@ void final_stats(void)
cputs(" 500 to 999|\r\n");
cputc('|');
- if (finalcash < 500)
+ if (score < 500)
{
revers(1);
}
@@ -1689,19 +1709,9 @@ void final_stats(void)
cputs("Play again? ");
choice = yngetc(0);
- /*
- while ((choice != 'Y') && (choice != 'y') &&
- (choice != 'N') && (choice != 'n'))
- {
- gotoxy(0, 22);
- cputs("Play again? ");
- choice = get_one();
- }
- */
-
if(choice == 'y') {
#ifdef BIGNUM
- bank = BIG_0;
+ big_copy(bank, big0);
#else
bank = 0;
#endif
@@ -1726,7 +1736,6 @@ void final_stats(void)
return;
}
-#endif
/* restore ROM character set. TODO: save old PEEK(756)
in newtitle.s, restore that here instead of using
hardcoded value. */
@@ -2336,11 +2345,11 @@ void elder_brother_wu(void)
cputs("borrow? ");
wu = get_num();
- if (wu == -1)
+ if(wu == -1)
{
wu = (cash * 2);
}
- if (wu <= (cash * 2))
+ if((wu <= (cash * 2)) && !would_overflow(cash, wu))
{
cash += wu;
debt += wu;
@@ -2708,6 +2717,12 @@ void sell(void) {
{
amount = hold_[choice];
}
+
+ if(would_overflow(cash, amount)) {
+ too_much_cash();
+ continue;
+ }
+
if (hold_[choice] >= amount)
{
hold_[choice] -= amount;
@@ -2721,6 +2736,18 @@ void sell(void) {
return;
}
+char would_overflow(unsigned long a, unsigned long b) {
+ return ((UINT32_MAX - b) <= a);
+}
+
+void too_much_cash(void) {
+ cputs("\r\nYou cannot carry so much cash, Taipan!");
+ cputs("\r\nYour ship would sink under the weight");
+ cputs("\r\nof your riches.\r\n");
+ bad_joss_sound();
+ timed_getch(TMOUT_3S);
+}
+
void visit_bank(void)
{
long amount = 0;
@@ -2772,6 +2799,8 @@ void visit_bank(void)
ulong_to_big(cash, bigcash);
big_sub(biglimit, big_max_ulong, bigcash);
+
+ /*
cputs("\rcash ");
cprintfancy_big(bigcash);
agetc();
@@ -2781,11 +2810,10 @@ void visit_bank(void)
cputs("\rlimit ");
cprintfancy_big(biglimit);
agetc();
+ */
+
if(big_cmp(bigamt, biglimit) >= 0) {
-// hangx: goto hangx;
- cputs("\r\nYou cannot carry so much cash, Taipan!");
- bad_joss_sound();
- timed_getch(TMOUT_1S);
+ too_much_cash();
continue;
}