diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | messages.pl | 191 | ||||
-rw-r--r-- | taipan.c | 469 | ||||
-rw-r--r-- | textcomp.c | 126 | ||||
-rw-r--r-- | textdecomp.s | 93 |
6 files changed, 720 insertions, 171 deletions
@@ -1,3 +1,6 @@ +msg.out +msg.tmp +textcomp memdump.dat rodata.8000 romable_taimain.raw @@ -99,7 +99,7 @@ XEX=taipan.xex # All the C and asm sources for taimain.xex: TAIMAIN_HDRS=sounds.h TAIMAIN_C_SRC=taipan.c strtonum.c -TAIMAIN_ASM_SRC=rand.s draw_lorcha.s timed_getch.s portstat.s console.s ultostr.s soundasm.s explosion.s +TAIMAIN_ASM_SRC=rand.s draw_lorcha.s timed_getch.s portstat.s console.s ultostr.s soundasm.s explosion.s textdecomp.s TAIMAIN_LIBS=conio/conio.lib # Comment these lines out to build without big number support. @@ -292,6 +292,13 @@ PORTSTAT.DAT: mkportstats.xex convfont: convfont.c $(HOSTCC) $(HOSTCFLAGS) -DFONT_ADDR=$(FONT_ADDR) -o convfont convfont.c +# text compressor +textcomp: textcomp.c + $(HOSTCC) $(HOSTCFLAGS) -o textcomp textcomp.c + +# messages.c is a generated file +messages.c: messages.pl textcomp + perl messages.pl > messages.c ### Cartridge-related targets. The way I'm doing this isn't 'proper': I should # be using cc65's linker with a fancy config script to do the bank layout diff --git a/messages.pl b/messages.pl new file mode 100644 index 0000000..0fd871f --- /dev/null +++ b/messages.pl @@ -0,0 +1,191 @@ +#!/usr/bin/perl -w + +# compresses messages for taipan.c. +# messages are listed at the end of this file after __END__ marker. +# output of this script should be redirected to messages.c. + +print "// do not edit, contents are generated by messages.pl\n\n"; + +while(<DATA>) { + chomp; + $msgcount++; + /^(\w+)\s/; + my $label = $1; + s/^\w+\s+//; + + my $orig = $_; + s/"//g; + s/\\r//g; + s/\\n/\n/g; + # warn "msg: $_\n"; + + $total_in += (1 + length); + open my $out, ">msg.out" or die $!; + print $out $_; + close $out; + system("./textcomp < msg.out > msg.tmp 2>/dev/null"); + open my $result, "<msg.tmp" or die $!; + print "const char M_$label\[\] = {\n\t// $orig\n\t"; + my $readbytes; + while(<$result>) { + my @got = split " ", $_; + $readbytes = @got; + print join(", ", @got); + $total_out += @got; + } + die "failed to compress $orig\n" unless $readbytes; + print "\n};\n\n"; +} + +print "// messages: $msgcount\n"; +print "// total input size: $total_in\n"; +print "// total output size: $total_out\n"; +print "// compression: " . ($total_in - $total_out) . "\n"; +print "// ratio: " . sprintf("%.1f", $total_out * 100 / $total_in) . "%\n"; + +# commented-out messages can go in the pod section below: +=pod +=cut + +__END__ +how_much_spc "How much " +will_you "will you " +bad_joss "Bad Joss!!\r\n" +crlf "\n" +taipan "Taipan" +do_you_wish "do you wish " +elder_brother_wu "Elder Brother Wu " +li_yuen "Li Yuen" +do_you_want "Do you want " +firm_colon "Firm:" +compradors_report "Comprador's Report\r\n\n" +captains_report " Captain's Report\r\n\n" +overloaded "Your ship is overloaded" +wish_to_trade "Do you wish to trade in your " +ship_for_one "\r\nship for one with " +more_capacity " more capacity by\r\npaying an additional " +gun_offer "Do you wish to buy a ship's gun\r\nfor " +space_ship " ship" +space_attacking " attacking" +your_orders_are "Your orders are: " +we_have " We have" +cur_seaworth "Current seaworthiness: " +what_shall_we_do "what shall we do??\r\n(Fight, Run, Throw cargo)" +aye_fight "Aye, we'll fight 'em" +were_firing "We're firing on 'em" +of_the_buggers " of the buggers" +didnt_sink "Hit 'em, but didn't sink 'em" +ran_away " ran away" +we_have_no_guns "We have no guns" +you_have_on_board "You have the following on board" +what_shall_i_throw "What shall I throw overboard" +how_much "How much" +hope_we_lose_em "Let's hope we lose 'em" +nothing_there "There's nothing there" +aye_run "Aye, we'll run" +we_got_away "We got away from 'em" +couldnt_lose_em "Couldn't lose 'em." +but_we_escaped "But we escaped from " +of_em " of 'em!" +theyre_firing "They're firing on us" +weve_been_hit "We've been hit" +buggers_hit_gun "The buggers hit a gun" +we_got_em_all "We got 'em all" +to_start "to start . . .\r\n\n" +with_cash ") With cash (and a debt)\r\n\n" +with_5_guns ") With five guns and no cash\r\n" +but_no_debt "(But no debt!)" +mchenry_has_arrived "Mc Henry from the Hong Kong\r\nShipyards has arrived!! He says, 'I see\r\nye've a wee bit of damage to yer ship.'\r\nWill ye be wanting repairs? " +tis_a_pity "Och, 'tis a pity to be " +percent_damaged "% damaged.\r\nWe can fix yer whole ship for " +or_partial_repairs ",\r\nor make partial repairs if you wish.\r\n" +will_ye_spend "will ye spend? " +illionaire " I L L I O N A I R E !" +youre_a " Y o u ' r e a" +your_final_status "Your final status:\r\n\nNet cash: " +ship_size "\r\nShip size: " +units_with " units with " +you_traded_for " guns\r\n\nYou traded for " +your_score_is "Your score is " +land_based_job "Have you considered a land based job?\r\n\n\n" +stay_on_shore "The crew has requested that you stay on\r\nshore for their safety!!\r\n\n" +your_rating "Your Rating:\r\n" +ma_tsu "Ma Tsu" +master_taipan "Master Taipan" +compradore "Compradore" +galley_hand "Galley Hand" +play_again "Play again? " +you_have_only "You have only " +you_have_no_cargo "You have no cargo" +move_to_whouse " shall I move\r\nto the warehouse" +whouse_only_hold "Your warehouse will only hold an\r\nadditional " +whouse_full "Your warehouse is full" +move_aboard " shall I move\r\naboard ship" +me_to_go_to "me to go to:\r\n" +already_here "\r\n\nYou're already here" +hostile_ship " hostile ship" +approaching " approaching" +fleet_drove_off "'s fleet drove them off!" +s_pirates "'s pirates" +they_let_us_be "Good joss!! They let us be!!\r\n" +ships_of_fleet " ships of Li Yuen's pirate\r\nfleet" +captured_some_booty "We captured some booty.\r\nIt's worth " +we_made_it "We made it!" +buggers_got_us "The buggers got us" +all_over_now "!\r\nIt's all over, now!!!" +storm "Storm" +think_going_down " I think we're going down!!\r\n\n" +were_going_down "We're going down" +storm_we_made_it " We made it!!\r\n\n" +blown_off_course "We've been blown off course\r\nto " +arriving_at "Arriving at " +asks " asks " +in_donation " in donation\r\nto the temple of Tin Hau, the Sea\r\nGoddess. Will you pay? " +not_enough_cash "you do not have enough cash!!\r\n\n" +make_up_difference "to make up\r\nthe difference for you? " +given_the_diff "has given Li Yuen the\r\ndifference between what he wanted and\r\nyour cash on hand and added the same\r\namount to your debt.\r\n" +very_well "Very well. " +will_not_pay "will not pay\r\nLi Yuen the difference. I would be very\r\nwary of pirates if I were you." +you_only_have "you only have " +do_you_have_biz_with_wu "Do you have business with Elder Brother\r\nWu, the moneylender? " +aware_of_your_plight "Elder Brother is aware of your plight,\r\nTaipan. He is willing to loan you an\r\nadditional " +if_you_will_pay_back " if you will pay back\r\n" +are_you_willing ". Are you willing" +game_is_over "Very well, Taipan, the game is over!\r\n" +very_well_good_joss "Very well, Taipan. Good joss!!\r\n" +to_repay_him "to repay\r\nhim? " +to_borrow "to \r\nborrow? " +wont_loan "\r\n\nHe won't loan you so much" +bodyguards_killed " of your bodyguards have been killed\r\nby cutthroats and you have been robbed\r\nof all of your cash" +the_price_of "!! The price of " +risen "risen" +dropped "dropped" +spc_to_spc " to " +prices_here_are "present prices per unit here are" +general_shortname "General" +shall_i_buy_sell "Shall I Buy, Sell, " +bank_transfer "Visit bank, Transfer\r\ncargo, " +quit_traging "Quit trading" +or_retire ", or Retire" +what_will_you_name_firm " What will you name your" +spc_you_can_spc " You can " +spc_shall " shall" +spc_afford " afford " +i_buy "I buy, " +shall_i_sell " shall\r\nI sell, " +too_much_cash "\r\nYou cannot carry so much cash" +ship_would_sink "\r\nYour ship would sink under the weight\r\nof your riches.\r\n" +deposit "deposit? " +withdraw "withdraw? " +assassinated_1 "you have been assassinated!" +assassinated_2 "As the masked figure plunges the blade\r\ninto your heart, he says:\r\n" +assassinated_3 "regrets to inform you\r\nthat your account has been terminated\r\nwith extreme prejudice." +has_sent "has sent " +braves_to_escort " braves\r\nto escort you to the Wu mansion" +wu_warn_1 "reminds you of the\r\nConfucian ideal of personal worthiness,\r\nand how this applies to paying one's\r\ndebts.\r\n" +wu_warn_2 "He is reminded of a fabled barbarian\r\nwho came to a bad end, after not caring\r\nfor his obligations.\r\n\nHe hopes no such fate awaits you, his\r\nfriend" +siezed_opium "The local authorities have seized your\r\nOpium cargo and have also fined you\r\n" +whouse_theft "Messenger reports large theft\r\nfrom warehouse" +has_sent_lieutenant " has sent a Lieutenant,\r\nTaipan. He says his admiral wishes\r\nto see you in Hong Kong, posthaste!\r\n" +beaten_robbed "You've been beaten up and\r\nrobbed of " +in_cash " in cash" @@ -162,6 +162,10 @@ void atari_text_setup() { /**** End of atari-specific stuff. Supposed to be, anyway. */ +#include "messages.c" + +extern void __fastcall__ print_msg(const char *msg); + /* old version of this used to just 'return randl()%clamp'. If clamp were 0, the return value would be the unclamped result from randl() (x % 0 == x, in cc65). If it were 1, @@ -404,24 +408,29 @@ long damage = 0, capacity = 60, newdamage; might or might not be worth turning into a function. */ void how_much(void) { - cputs("How much "); + // cputs("How much "); + print_msg(M_how_much_spc); } void how_much_will_you(void) { how_much(); - cputs("will you "); + // cputs("will you "); + print_msg(M_will_you); } void cprint_bad_joss() { - cputs("Bad Joss!!\r\n"); + // cputs("Bad Joss!!\r\n"); + print_msg(M_bad_joss); } void crlf(void) { - cputs("\r\n"); + // cputs("\r\n"); + print_msg(M_crlf); } void cprint_taipan(void) { - cputs("Taipan"); + // cputs("Taipan"); + print_msg(M_taipan); } void comma_space(void) { @@ -474,25 +483,30 @@ void cprint_taipan_prompt(void) { } void do_you_wish(void) { - cputs("do you wish "); + // cputs("do you wish "); + print_msg(M_do_you_wish); } void cprint_elder_brother_wu(void) { - cputs("Elder Brother Wu "); + // cputs("Elder Brother Wu "); + print_msg(M_elder_brother_wu); } /* This one only saves space when Li Yuen occurs at the start of a string, not in the middle */ void cprint_li_yuen(void) { - cputs("Li Yuen"); + // cputs("Li Yuen"); + print_msg(M_li_yuen); } void cprint_Do_you_want(void) { - cputs("Do you want "); + // cputs("Do you want "); + print_msg(M_do_you_want); } void cprint_firm_colon(void) { - cputs("Firm:"); + // cputs("Firm:"); + print_msg(M_firm_colon); } /* making this a function saved 52 bytes */ @@ -604,12 +618,14 @@ void prepare_report(void) { void compradores_report(void) { prepare_report(); - cputs("Comprador's Report\r\n\n"); + // cputs("Comprador's Report\r\n\n"); + print_msg(M_compradors_report); } void captains_report(void) { prepare_report(); - cputs(" Captain's Report\r\n\n"); + // cputs(" Captain's Report\r\n\n"); + print_msg(M_captains_report); } void clear_msg_window(void) { @@ -619,7 +635,8 @@ void clear_msg_window(void) { void overload(void) { compradores_report(); - cputs("Your ship is overloaded"); + // cputs("Your ship is overloaded"); + print_msg(M_overloaded); cprint_taipan_bangbang(); good_joss_sound(); timed_getch(); @@ -640,13 +657,17 @@ void new_ship(void) { } compradores_report(); - cputs("Do you wish to trade in your "); + // cputs("Do you wish to trade in your "); + print_msg(M_wish_to_trade); if(damage > 0) { cputs("\xe4\xe1\xed\xe1\xe7\xe5\xe4"); // inverse "damaged" } else { cputs("fine"); } - cputs("\r\nship for one with 50 more capacity by\r\npaying an additional "); + // cputs("\r\nship for one with 50 more capacity by\r\npaying an additional "); + print_msg(M_ship_for_one); + cprintulong(50); + print_msg(M_more_capacity); cprintfancy(amount); cprint_taipan_prompt(); @@ -676,7 +697,8 @@ void new_gun(void) { } compradores_report(); - cputs("Do you wish to buy a ship's gun\r\nfor "); + // cputs("Do you wish to buy a ship's gun\r\nfor "); + print_msg(M_gun_offer); cprintfancy(amount); cprint_taipan_prompt(); @@ -807,14 +829,17 @@ void fight_stats(int ships, int orders) { gotoxy(0, 0); justify_int(ships); - cputs(" ship"); + // cputs(" ship"); + print_msg(M_space_ship); if(ships != 1) cputc_s(); - cputs(" attacking"); + // cputs(" attacking"); + print_msg(M_space_attacking); cprint_taipan_bang(); cspace(); crlf(); - cputs("Your orders are: "); + // cputs("Your orders are: "); + print_msg(M_your_orders_are); cblank(11); switch(orders) { case 1: cputs("Fight"); break; @@ -895,7 +920,8 @@ char sea_battle(char id, int num_ships) { updates are smoother-looking. Maybe. */ rvs_on(); gotoxy(30, 0); - cputs(" We have"); + // cputs(" We have"); + print_msg(M_we_have); gotoxy(30, 1); cspaces(6); cputs("guns"); @@ -919,7 +945,8 @@ char sea_battle(char id, int num_ships) { gotoxy(0, 3); clrtoeol(); - cputs("Current seaworthiness: "); + // cputs("Current seaworthiness: "); + print_msg(M_cur_seaworth); cputs(st[status / 20]); cputs(" ("); cprintulong(status); @@ -972,13 +999,15 @@ char sea_battle(char id, int num_ships) { ik = 1; gotoxy(0, 3); clrtoeol(); - cputs("Aye, we'll fight 'em"); + // cputs("Aye, we'll fight 'em"); + print_msg(M_aye_fight); cprint_taipan_period(); set_orders(); gotoxy(0, 3); clrtoeol(); - cputs("We're firing on 'em"); + // cputs("We're firing on 'em"); + print_msg(M_were_firing); cprint_taipan_bang(); set_orders(); @@ -1047,11 +1076,13 @@ char sea_battle(char id, int num_ships) { if(sk > 0) { cputs("Sunk "); cprintulong(sk); - cputs(" of the buggers"); + // cputs(" of the buggers"); + print_msg(M_of_the_buggers); cprint_taipan_bang(); bad_joss_sound(); } else { - cputs("Hit 'em, but didn't sink 'em"); + // cputs("Hit 'em, but didn't sink 'em"); + print_msg(M_didnt_sink); cprint_taipan_bang(); } set_orders(); @@ -1067,7 +1098,8 @@ char sea_battle(char id, int num_ships) { gotoxy(0, 3); clrtoeol(); cprintulong(ran); - cputs(" ran away"); + // cputs(" ran away"); + print_msg(M_ran_away); cprint_taipan_bang(); bad_joss_sound(); @@ -1093,7 +1125,8 @@ char sea_battle(char id, int num_ships) { } else if ((orders == 1) && (guns == 0)) { gotoxy(0, 3); clrtoeol(); - cputs("We have no guns"); + // cputs("We have no guns"); + print_msg(M_we_have_no_guns); cprint_taipan_bangbang(); set_orders(); } else if (orders == 3) { @@ -1102,7 +1135,8 @@ char sea_battle(char id, int num_ships) { total = 0; gotoxy(0, 3); - cputs("You have the following on board"); + // cputs("You have the following on board"); + print_msg(M_you_have_on_board); cprint_taipan_colon(); gotoxy(4, 4); cputs(item[0]); @@ -1123,7 +1157,8 @@ char sea_battle(char id, int num_ships) { gotoxy(0, 6); clrtoeol(); - cputs("What shall I throw overboard"); + // cputs("What shall I throw overboard"); + print_msg(M_what_shall_i_throw); cprint_taipan_prompt(); choice = get_item(1); @@ -1131,7 +1166,8 @@ char sea_battle(char id, int num_ships) { if(choice < 4) { gotoxy(0, 6); clrtoeol(); - cputs("How much"); + // cputs("How much"); + print_msg(M_how_much); cprint_taipan_prompt(); amount = get_num(); @@ -1154,7 +1190,8 @@ char sea_battle(char id, int num_ships) { if(total > 0) { gotoxy(0, 3); clrtoeol(); - cputs("Let's hope we lose 'em"); + // cputs("Let's hope we lose 'em"); + print_msg(M_hope_we_lose_em); cprint_taipan_bang(); bad_joss_sound(); if (choice < 4) { @@ -1174,7 +1211,8 @@ char sea_battle(char id, int num_ships) { } else { gotoxy(0, 3); clrtoeol(); - cputs("There's nothing there"); + // cputs("There's nothing there"); + print_msg(M_nothing_there); cprint_taipan_bang(); good_joss_sound(); @@ -1186,7 +1224,8 @@ char sea_battle(char id, int num_ships) { if(orders == 2) { gotoxy(0, 3); clrtoeol(); - cputs("Aye, we'll run"); + // cputs("Aye, we'll run"); + print_msg(M_aye_run); cprint_taipan_period(); set_orders(); } @@ -1195,7 +1234,8 @@ char sea_battle(char id, int num_ships) { if(randi()%ok > randi()%num_ships) { gotoxy(0, 3); clrtoeol(); - cputs("We got away from 'em"); + // cputs("We got away from 'em"); + print_msg(M_we_got_away); cprint_taipan_bang(); good_joss_sound(); set_orders(); @@ -1203,7 +1243,8 @@ char sea_battle(char id, int num_ships) { } else { gotoxy(0, 3); clrtoeol(); - cputs("Couldn't lose 'em."); + // cputs("Couldn't lose 'em."); + print_msg(M_couldnt_lose_em); set_orders(); if((num_ships > 2) && (one_chance_in(5))) { @@ -1214,9 +1255,11 @@ char sea_battle(char id, int num_ships) { fight_stats(num_ships, orders); gotoxy(0, 3); clrtoeol(); - cputs("But we escaped from "); + // cputs("But we escaped from "); + print_msg(M_but_we_escaped); cprintulong(lost); - cputs(" of 'em!"); + // cputs(" of 'em!"); + print_msg(M_of_em); if(num_ships <= 10) { for(i = 9; i >= 0; i--) { @@ -1241,11 +1284,11 @@ char sea_battle(char id, int num_ships) { if(num_ships > 0) { gotoxy(0, 3); clrtoeol(); - cputs("They're firing on us"); + // cputs("They're firing on us"); + print_msg(M_theyre_firing); cprint_taipan_bang(); set_orders(); - // hide_cursor(); explosion(); fight_stats(num_ships, orders); @@ -1253,7 +1296,8 @@ char sea_battle(char id, int num_ships) { gotoxy(0, 3); clrtoeol(); - cputs("We've been hit"); + // cputs("We've been hit"); + print_msg(M_weve_been_hit); cprint_taipan_bangbang(); under_attack_sound(); @@ -1274,7 +1318,8 @@ char sea_battle(char id, int num_ships) { fight_stats(num_ships, orders); gotoxy(0, 3); clrtoeol(); - cputs("The buggers hit a gun"); + // cputs("The buggers hit a gun"); + print_msg(M_buggers_hit_gun); cprint_taipan_bangbang(); under_attack_sound(); fight_stats(num_ships, orders); @@ -1335,11 +1380,11 @@ char sea_battle(char id, int num_ships) { } if(orders == 1) { - // clr_screen(); fight_stats(num_ships, orders); gotoxy(0, 3); clrtoeol(); - cputs("We got 'em all"); + // cputs("We got 'em all"); + print_msg(M_we_got_em_all); cprint_taipan_bang(); bad_joss_sound(); timed_getch(); @@ -1394,13 +1439,18 @@ void cash_or_guns(void) { clr_screen(); cprint_Do_you_want(); - cputs("to start . . .\r\n\n"); - cputs(" 1) With cash (and a debt)\r\n\n"); + // cputs("to start . . .\r\n\n"); + print_msg(M_to_start); + // cputs(" 1) With cash (and a debt)\r\n\n"); + cputs(" 1"); + print_msg(M_with_cash); cspaces(16); - cputs("-- or --\r\n\n"); - cputs(" 2) With five guns and no cash\r\n"); + cputs("-- or --\r\n\n 2"); + // cputs(" 2) With five guns and no cash\r\n"); + print_msg(M_with_5_guns); cspaces(16); - cputs("(But no debt!)"); + // cputs("(But no debt!)"); + print_msg(M_but_no_debt); gotoxy(10, 10); cputc('?'); @@ -1639,10 +1689,13 @@ void port_stats(void) void mchenry(void) { compradores_report(); cprint_taipan_comma(); + /* cputs("Mc Henry from the Hong Kong\r\n" "Shipyards has arrived!! He says, 'I see\r\n" "ye've a wee bit of damage to yer ship.'\r\n" "Will ye be wanting repairs? "); + */ + print_msg(M_mchenry_has_arrived); if(yngetc('y') == 'y') { static int percent, time; @@ -1661,13 +1714,17 @@ void mchenry(void) { repair_price = (br * damage) + 1; clear_msg_window(); - cputs("Och, 'tis a pity to be "); + // cputs("Och, 'tis a pity to be "); + print_msg(M_tis_a_pity); cprintulong(percent); - cputs("% damaged.\r\nWe can fix yer whole ship for "); + // cputs("% damaged.\r\nWe can fix yer whole ship for "); + print_msg(M_percent_damaged); cprintulong(repair_price); - cputs(",\r\nor make partial repairs if you wish.\r\n"); + // cputs(",\r\nor make partial repairs if you wish.\r\n"); + print_msg(M_or_partial_repairs); how_much(); - cputs("will ye spend? "); + // cputs("will ye spend? "); + print_msg(M_will_ye_spend); for (;;) { gotoxy(24, 21); @@ -1727,7 +1784,8 @@ void aire(void) { cputs("T R"); endspace = 0; } - cputs(" I L L I O N A I R E !"); + // cputs(" I L L I O N A I R E !"); + print_msg(M_illionaire); if(endspace) cspaces(2); crlf(); } @@ -1740,8 +1798,8 @@ void retire(void) { // crlf(); retire_blanks(); - // cputs(" Y o u ' r e a \r\n"); - cputs(" Y o u ' r e a"); + // cputs(" Y o u ' r e a"); + print_msg(M_youre_a); cspaces(9); crlf(); @@ -1802,19 +1860,23 @@ void final_stats(void) port_stat_dirty = 1; clr_screen(); - cputs("Your final status:\r\n\n" - "Net cash: "); + // cputs("Your final status:\r\n\n" + // "Net cash: "); + print_msg(M_your_final_status); #ifdef BIGNUM cprintfancy_big(finalcash); #else cprintfancy(finalcash); #endif - cputs("\r\nShip size: "); + // cputs("\r\nShip size: "); + print_msg(M_ship_size); cprintulong(capacity); - cputs(" units with "); + // cputs(" units with "); + print_msg(M_units_with); cprintulong(guns); - cputs(" guns\r\n\n" - "You traded for "); + // cputs(" guns\r\n\n" + // "You traded for "); + print_msg(M_you_traded_for); cprintulong(years); cputs(" year"); if (years != 1) @@ -1830,7 +1892,8 @@ void final_stats(void) } cputs("\r\n\n"); rvs_on(); - cputs("Your score is "); + // cputs("Your score is "); + print_msg(M_your_score_is); #ifdef BIGNUM cprintfancy_big(bigscore); #else @@ -1840,38 +1903,40 @@ void final_stats(void) rvs_off(); if ((score < 100) && (score >= 0)) { - cputs("Have you considered a land based job?\r\n\n\n"); + // cputs("Have you considered a land based job?\r\n\n\n"); + print_msg(M_land_based_job); } else if (score < 0) { - cputs("The crew has requested that you stay on\r\n" - "shore for their safety!!\r\n\n"); + // cputs("The crew has requested that you stay on\r\n" + // "shore for their safety!!\r\n\n"); + print_msg(M_stay_on_shore); } else { cputs("\r\n\n\n"); } - cputs("Your Rating:\r\n"); + // cputs("Your Rating:\r\n"); + print_msg(M_your_rating); cputc(17); // upper left corner chline(31); cputc(5); // upper right corner - // cputs("\r\n"); crlf(); cprint_pipe(); - // cputc('|'); if (score > 49999L) { rvs_on(); } - cputs("Ma Tsu"); + // cputs("Ma Tsu"); + print_msg(M_ma_tsu); rvs_off(); cspaces(9); cputs("50,000 and over |\r\n"); cprint_pipe(); - // cputc('|'); if ((score < 50000L) && (score > 7999L)) { rvs_on(); } - cputs("Master Taipan"); + // cputs("Master Taipan"); + print_msg(M_master_taipan); rvs_off(); cputs(" 8,000 to 49,999|\r\n"); cprint_pipe(); @@ -1881,30 +1946,29 @@ void final_stats(void) { rvs_on(); } - // cputs("Taipan"); cprint_taipan(); rvs_off(); cspaces(10); cputs("1,000 to 7,999|\r\n"); cprint_pipe(); - // cputc('|'); if ((score < 1000) && (score > 499)) { rvs_on(); } - cputs("Compradore"); + // cputs("Compradore"); + print_msg(M_compradore); rvs_off(); cspaces(8); cputs("500 to 999|\r\n"); cprint_pipe(); - // cputc('|'); if (score < 500) { rvs_on(); } - cputs("Galley Hand"); + // cputs("Galley Hand"); + print_msg(M_galley_hand); rvs_off(); cspaces(7); cputs("less than 500|\r\n"); @@ -1914,7 +1978,8 @@ void final_stats(void) cputc(3); // lower right corner gotoxy(0, 22); - cputs("Play again? "); + // cputs("Play again? "); + print_msg(M_play_again); choice = yngetc(0); if(choice == 'y') { @@ -1976,7 +2041,8 @@ char have_no_cargo(void) { } void you_have_only(void) { - cputs("You have only "); + // cputs("You have only "); + print_msg(M_you_have_only); } void transfer(void) @@ -1987,7 +2053,8 @@ void transfer(void) if(have_no_cargo()) { gotoxy(0, 22); clrtobot(); - cputs("You have no cargo"); + // cputs("You have no cargo"); + print_msg(M_you_have_no_cargo); cprint_taipan_period(); crlf(); good_joss_sound(); @@ -2005,7 +2072,8 @@ void transfer(void) compradores_report(); how_much(); cputs(item[i]); - cputs(" shall I move\r\nto the warehouse"); + // cputs(" shall I move\r\nto the warehouse"); + print_msg(M_move_to_whouse); cprint_taipan_prompt(); amount = get_num(); @@ -2025,12 +2093,14 @@ void transfer(void) break; } else if (in_use == 10000) { gotoxy(0, 21); - cputs("Your warehouse is full"); + // cputs("Your warehouse is full"); + print_msg(M_whouse_full); cprint_taipan_bang(); good_joss_sound(); } else { gotoxy(0, 21); - cputs("Your warehouse will only hold an\r\nadditional "); + // cputs("Your warehouse will only hold an\r\nadditional "); + print_msg(M_whouse_only_hold); cprintulong(10000 - in_use); cprint_taipan_bang(); good_joss_sound(); @@ -2060,7 +2130,8 @@ void transfer(void) compradores_report(); how_much(); cputs(item[i]); - cputs(" shall I move\r\naboard ship"); + // cputs(" shall I move\r\naboard ship"); + print_msg(M_move_aboard); cprint_taipan_prompt(); amount = get_num(); @@ -2105,7 +2176,8 @@ void quit(void) compradores_report(); cprint_taipan_comma(); do_you_wish(); - cputs("me to go to:\r\n"); + // cputs("me to go to:\r\n"); + print_msg(M_me_to_go_to); for(choice = 1; choice < 8; ++choice) { if(choice == 7) crlf(); @@ -2131,7 +2203,8 @@ void quit(void) if (choice == port) { - cputs("\r\n\nYou're already here"); + // cputs("\r\n\nYou're already here"); + print_msg(M_already_here); cprint_taipan_period(); good_joss_sound(); timed_getch(); @@ -2157,10 +2230,11 @@ void quit(void) num_ships = 9999; } cprintulong(num_ships); - cputs(" hostile ship"); + // cputs(" hostile ship"); + print_msg(M_hostile_ship); if(num_ships != 1) cputc_s(); - // cputs(" approaching, Taipan!\r\n"); - cputs(" approaching"); + // cputs(" approaching"); + print_msg(M_approaching); cprint_taipan_bang(); crlf(); under_attack_sound(); @@ -2178,7 +2252,8 @@ void quit(void) captains_report(); cprint_li_yuen(); - cputs("'s fleet drove them off!"); + // cputs("'s fleet drove them off!"); + print_msg(M_fleet_drove_off); timed_getch(); } @@ -2187,9 +2262,9 @@ void quit(void) { clear_msg_window(); cprint_li_yuen(); - cputs("'s pirates"); + // cputs("'s pirates"); + print_msg(M_s_pirates); cprint_taipan_bangbang(); - // cputs("\r\n"); crlf(); crlf(); bad_joss_sound(); @@ -2198,7 +2273,8 @@ void quit(void) if (li > 0) { - cputs("Good joss!! They let us be!!\r\n"); + // cputs("Good joss!! They let us be!!\r\n"); + print_msg(M_they_let_us_be); bad_joss_sound(); timed_getch(); @@ -2211,7 +2287,8 @@ void quit(void) cprintulong(num_ships); /* "ships" will always be plural (at least 5 of them) */ - cputs(" ships of Li Yuen's pirate\r\nfleet"); + // cputs(" ships of Li Yuen's pirate\r\nfleet"); + print_msg(M_ships_of_fleet); cprint_taipan_bangbang(); under_attack_sound(); timed_getch(); @@ -2234,21 +2311,23 @@ void quit(void) captains_report(); if (result == 1) { - // fancy_numbers(booty, fancy_num); - cputs("We captured some booty.\r\n" - "It's worth "); - // cputs(fancy_num); + // cputs("We captured some booty.\r\n" + // "It's worth "); + print_msg(M_captured_some_booty); cprintfancy(booty); cprint_bang(); cash += booty; good_joss_sound(); } else if (result == 3) { - cputs("We made it!"); + // cputs("We made it!"); + print_msg(M_we_made_it); good_joss_sound(); } else { - cputs("The buggers got us"); + // cputs("The buggers got us"); + print_msg(M_buggers_got_us); cprint_taipan_bangbang(); - cputs("!\r\nIt's all over, now!!!"); + // cputs("!\r\nIt's all over, now!!!"); + print_msg(M_all_over_now); timed_getch(); @@ -2261,18 +2340,17 @@ void quit(void) if(one_chance_in(10)) { clear_msg_window(); - // gotoxy(0, 18); - // clrtobot(); - cputs("Storm"); + // cputs("Storm"); + print_msg(M_storm); cprint_taipan_bangbang(); - // cputs("\r\n"); crlf(); crlf(); bad_joss_sound(); timed_getch(); if(one_chance_in(30)) { - cputs(" I think we're going down!!\r\n\n"); + // cputs(" I think we're going down!!\r\n\n"); + print_msg(M_think_going_down); timed_getch(); // if (((damage / capacity * 3) * ((float) randi() / RAND_MAX)) >= 1) @@ -2290,9 +2368,9 @@ void quit(void) sunk = randclamp(3) != 0; if(sunk) { - cputs("We're going down"); + // cputs("We're going down"); + print_msg(M_were_going_down); cprint_taipan_bangbang(); - // cputs("\r\n"); crlf(); under_attack_sound(); timed_getch(); @@ -2301,7 +2379,8 @@ void quit(void) } } - cputs(" We made it!!\r\n\n"); + // cputs(" We made it!!\r\n\n"); + print_msg(M_storm_we_made_it); bad_joss_sound(); timed_getch(); @@ -2312,7 +2391,8 @@ void quit(void) port = randi()%7 + 1; clear_msg_window(); - cputs("We've been blown off course\r\nto "); + // cputs("We've been blown off course\r\nto "); + print_msg(M_blown_off_course); cputs(location[port]); timed_getch(); } @@ -2375,9 +2455,8 @@ void quit(void) set_prices(); clear_msg_window(); - // gotoxy(0, 18); - // clrtobot(); - cputs("Arriving at "); + // cputs("Arriving at "); + print_msg(M_arriving_at); cputs(location[port]); cputs("..."); timed_getch(); @@ -2409,9 +2488,11 @@ void li_yuen_extortion(void) { compradores_report(); cprint_li_yuen(); - cputs(" asks "); + // cputs(" asks "); + print_msg(M_asks); cprintfancy(amount); - cputs(" in donation\r\nto the temple of Tin Hau, the Sea\r\nGoddess. Will you pay? "); + // cputs(" in donation\r\nto the temple of Tin Hau, the Sea\r\nGoddess. Will you pay? "); + print_msg(M_in_donation); if(yngetc(0) == 'y') { if(amount <= cash) { @@ -2419,20 +2500,17 @@ void li_yuen_extortion(void) { li = 1; } else { clear_msg_window(); - // gotoxy(0, 18); - // clrtobot(); cprint_taipan_comma(); - cputs("you do not have enough cash!!\r\n\n"); + // cputs("you do not have enough cash!!\r\n\n"); + print_msg(M_not_enough_cash); timed_getch(); cprint_Do_you_want(); cprint_elder_brother_wu(); - cputs("to make up\r\nthe difference for you? "); + // cputs("to make up\r\nthe difference for you? "); + print_msg(M_make_up_difference); - // clear_msg_window(); - // gotoxy(0, 18); - // clrtobot(); if(yngetc(0) == 'y') { clear_msg_window(); amount -= cash; @@ -2441,18 +2519,25 @@ void li_yuen_extortion(void) { li = 1; cprint_elder_brother_wu(); + /* cputs("has given Li Yuen the\r\n" "difference between what he wanted and\r\n" "your cash on hand and added the same\r\n" "amount to your debt.\r\n"); + */ + print_msg(M_given_the_diff); } else { clear_msg_window(); cash = 0; - cputs("Very well. "); + // cputs("Very well. "); + print_msg(M_very_well); cprint_elder_brother_wu(); + /* cputs("will not pay\r\n" "Li Yuen the difference. I would be very\r\n" "wary of pirates if I were you."); + */ + print_msg(M_will_not_pay); cprint_taipan_period(); crlf(); } @@ -2466,11 +2551,10 @@ void li_yuen_extortion(void) { #ifdef BIGNUM void you_only_have(unsigned char in_bank) { clear_msg_window(); - // gotoxy(0, 18); - // clrtobot(); cprint_taipan_comma(); - cputs("you only have "); + // cputs("you only have "); + print_msg(M_you_only_have); if(in_bank) cprintfancy_big(bank); else @@ -2507,7 +2591,8 @@ void elder_brother_wu(void) unsigned long wu = 0; compradores_report(); - cputs("Do you have business with Elder Brother\r\nWu, the moneylender? "); + // cputs("Do you have business with Elder Brother\r\nWu, the moneylender? "); + print_msg(M_do_you_have_biz_with_wu); for (;;) { @@ -2536,19 +2621,25 @@ void elder_brother_wu(void) for (;;) { compradores_report(); + /* cputs("Elder Brother is aware of your plight,\r\n" "Taipan. He is willing to loan you an\r\n" "additional "); + */ + print_msg(M_aware_of_your_plight); cprintulong(i); - cputs(" if you will pay back\r\n"); + // cputs(" if you will pay back\r\n"); + print_msg(M_if_you_will_pay_back); cprintulong(j); - cputs(". Are you willing"); + // cputs(". Are you willing"); + print_msg(M_are_you_willing); cprint_taipan_prompt(); choice = agetc(); if(choice != 'y') { compradores_report(); - cputs("Very well, Taipan, the game is over!\r\n"); + // cputs("Very well, Taipan, the game is over!\r\n"); + print_msg(M_game_is_over); under_attack_sound(); timed_getch(); @@ -2560,7 +2651,8 @@ void elder_brother_wu(void) port_stats(); compradores_report(); - cputs("Very well, Taipan. Good joss!!\r\n"); + // cputs("Very well, Taipan. Good joss!!\r\n"); + print_msg(M_very_well_good_joss); bad_joss_sound(); timed_getch(); @@ -2574,7 +2666,8 @@ void elder_brother_wu(void) compradores_report(); how_much(); do_you_wish(); - cputs("to repay\r\nhim? "); + // cputs("to repay\r\nhim? "); + print_msg(M_to_repay_him); wu = get_num(); if(wu == UINT32_MAX) @@ -2607,7 +2700,8 @@ void elder_brother_wu(void) compradores_report(); how_much(); do_you_wish(); - cputs("to \r\nborrow? "); + // cputs("to \r\nborrow? "); + print_msg(M_to_borrow); wu = get_num(); @@ -2622,7 +2716,8 @@ void elder_brother_wu(void) debt += wu; break; } else { - cputs("\r\n\nHe won't loan you so much"); + // cputs("\r\n\nHe won't loan you so much"); + print_msg(M_wont_loan); cprint_taipan_bang(); good_joss_sound(); timed_getch(); @@ -2646,9 +2741,12 @@ void elder_brother_wu(void) compradores_report(); cprint_bad_joss(); cprintulong(num); + /* cputs(" of your bodyguards have been killed\r\n" "by cutthroats and you have been robbed\r\n" "of all of your cash"); + */ + print_msg(M_bodyguards_killed); cprint_taipan_bangbang(); crlf(); under_attack_sound(); @@ -2663,21 +2761,25 @@ void good_prices(void) { unsigned char i = randi()%4; compradores_report(); - cprint_taipan_bangbang(); - cputs(" The price of "); + cprint_taipan(); + // cputs("!! The price of "); + print_msg(M_the_price_of); cputs(item[i]); cputs("\r\n has "); if(randi()&1) { price[i] *= (randi()%5 + 5); - cputs("risen"); + // cputs("risen"); + print_msg(M_risen); } else { price[i] /= 5; /* somehow general cargo dropped to 0 once. stop it. */ if(price[i] < 1) price[i] = 1; - cputs("dropped"); + // cputs("dropped"); + print_msg(M_dropped); } - cputs(" to "); + // cputs(" to "); + print_msg(M_spc_to_spc); cprintulong(price[i]); cputs("!!\r\n"); @@ -2693,7 +2795,8 @@ int port_choices(void) { compradores_report(); cprint_taipan_comma(); - cputs("present prices per unit here are"); /* NB: exactly 40 cols */ + // cputs("present prices per unit here are"); /* NB: exactly 40 cols */ + print_msg(M_prices_here_are); // ===> free code space $0f7b (3936, 3.9K) // saves 46 bytes: @@ -2754,16 +2857,19 @@ int port_choices(void) { retire_ok = (port == 1 && ((cash + bank) >= 1000000L)); #endif - cputs("Shall I Buy, Sell, "); + // cputs("Shall I Buy, Sell, "); + print_msg(M_shall_i_buy_sell); if(port == 1) - cputs("Visit bank, Transfer\r\ncargo, "); + // cputs("Visit bank, Transfer\r\ncargo, "); + print_msg(M_bank_transfer); if(!retire_ok) cputs("or "); cputs("Quit trading"); - if(retire_ok) cputs(", or Retire"); + // if(retire_ok) cputs(", or Retire"); + if(retire_ok) print_msg(M_or_retire); cprint_question_space(); for(;;) { @@ -2825,7 +2931,8 @@ void name_firm(void) { cprint_pipe(); print_bar_line(); cprint_pipe(); - cputs(" What will you name your"); + // cputs(" What will you name your"); + print_msg(M_what_will_you_name_firm); cspaces(14); cprint_pipe(); print_bar_line(); @@ -2908,15 +3015,18 @@ void buy(void) { afford = cash / price[choice]; rvs_on(); - cputs(" You can "); + // cputs(" You can "); + print_msg(M_spc_you_can_spc); rvs_off(); gotoxy(0, 22); how_much(); cputs(item[choice]); - cputs(" shall"); + // cputs(" shall"); + print_msg(M_spc_shall); gotoxy(31, 22); rvs_on(); - cputs(" afford "); + // cputs(" afford "); + print_msg(M_spc_afford); gotoxy(31, 23); // cspaces(9); // gotoxy(31, 23); @@ -2931,7 +3041,8 @@ void buy(void) { rvs_off(); gotoxy(0, 23); - cputs("I buy, "); + // cputs("I buy, "); + print_msg(M_i_buy); cprint_taipan_colon(); amount = get_num(); @@ -2962,7 +3073,8 @@ void sell(void) { how_much(); cputs(item[choice]); - cputs(" shall\r\nI sell, "); + // cputs(" shall\r\nI sell, "); + print_msg(M_shall_i_sell); cprint_taipan_colon(); amount = get_num(); @@ -2994,9 +3106,11 @@ char would_overflow(unsigned long a, unsigned long b) { void too_much_cash(void) { clear_msg_window(); - cputs("\r\nYou cannot carry so much cash"); + // cputs("\r\nYou cannot carry so much cash"); + print_msg(M_too_much_cash); cprint_taipan_bang(); - cputs("\r\nYour ship would sink under the weight\r\nof your riches.\r\n"); + // cputs("\r\nYour ship would sink under the weight\r\nof your riches.\r\n"); + print_msg(M_ship_would_sink); bad_joss_sound(); timed_getch(); } @@ -3014,7 +3128,8 @@ void visit_bank(void) { compradores_report(); how_much_will_you(); - cputs("deposit? "); + // cputs("deposit? "); + print_msg(M_deposit); amount = get_num(); if (amount == UINT32_MAX) @@ -3041,7 +3156,8 @@ void visit_bank(void) { compradores_report(); how_much_will_you(); - cputs("withdraw? "); + // cputs("withdraw? "); + print_msg(M_withdraw); amount = get_num(); #ifdef BIGNUM @@ -3160,18 +3276,21 @@ int main(void) { wu_assassin = 0; compradores_report(); cprint_taipan_comma(); - cputs("you have been assassinated!"); + // cputs("you have been assassinated!"); + print_msg(M_assassinated_1); under_attack_sound(); timed_getch(); compradores_report(); - cputs("As the masked figure plunges the blade\r\n" - "into your heart, he says:\r\n"); + // cputs("As the masked figure plunges the blade\r\n" + // "into your heart, he says:\r\n"); + print_msg(M_assassinated_2); timed_getch(); compradores_report(); cprint_elder_brother_wu(); - cputs("regrets to inform you\r\n" - "that your account has been terminated\r\n" - "with extreme prejudice."); + // cputs("regrets to inform you\r\n" + // "that your account has been terminated\r\n" + // "with extreme prejudice."); + print_msg(M_assassinated_3); timed_getch(); final_stats(); } @@ -3188,9 +3307,11 @@ int main(void) { compradores_report(); cprint_elder_brother_wu(); - cputs("has sent "); + // cputs("has sent "); + print_msg(M_has_sent); cprintulong(braves); - cputs(" braves\r\nto escort you to the Wu mansion"); + // cputs(" braves\r\nto escort you to the Wu mansion"); + print_msg(M_braves_to_escort); cprint_taipan_period(); crlf(); @@ -3198,17 +3319,23 @@ int main(void) { clear_msg_window(); cprint_elder_brother_wu(); + /* cputs("reminds you of the\r\n" "Confucian ideal of personal worthiness,\r\n" "and how this applies to paying one's\r\ndebts.\r\n"); + */ + print_msg(M_wu_warn_1); timed_getch(); clear_msg_window(); + /* cputs("He is reminded of a fabled barbarian\r\n" "who came to a bad end, after not caring\r\n" "for his obligations.\r\n\n" "He hopes no such fate awaits you, his\r\nfriend"); + */ + print_msg(M_wu_warn_2); cprint_taipan_period(); crlf(); @@ -3240,16 +3367,13 @@ int main(void) { port_stats(); - // fancy_numbers(fine, fancy_num); compradores_report(); - // cputs("Bad Joss!!\r\n"); cprint_bad_joss(); - cputs("The local authorities have seized your\r\n" - "Opium cargo and have also fined you\r\n"); - // cputs(fancy_num); + // cputs("The local authorities have seized your\r\n" + // "Opium cargo and have also fined you\r\n"); + print_msg(M_siezed_opium); cprintfancy(fine); cprint_taipan_bang(); - // cputs("\r\n"); crlf(); timed_getch(); @@ -3270,9 +3394,9 @@ int main(void) { port_stats(); compradores_report(); - cputs("Messenger reports large theft\r\nfrom warehouse"); + // cputs("Messenger reports large theft\r\nfrom warehouse"); + print_msg(M_whouse_theft); cprint_taipan_period(); - // cputs("\r\n"); crlf(); timed_getch(); @@ -3286,9 +3410,12 @@ int main(void) { if((port != 1) && (li == 0) && (!one_chance_in(4))) { compradores_report(); cprint_li_yuen(); + /* cputs(" has sent a Lieutenant,\r\n" "Taipan. He says his admiral wishes\r\n" "to see you in Hong Kong, posthaste!\r\n"); + */ + print_msg(M_has_sent_lieutenant); bad_joss_sound(); timed_getch(); } @@ -3306,9 +3433,11 @@ int main(void) { compradores_report(); cprint_bad_joss(); - cputs("You've been beaten up and\r\nrobbed of "); + // cputs("You've been beaten up and\r\nrobbed of "); + print_msg(M_beaten_robbed); cprintfancy(robbed); - cputs(" in cash"); + // cputs(" in cash"); + print_msg(M_in_cash); cprint_taipan_bangbang(); crlf(); under_attack_sound(); diff --git a/textcomp.c b/textcomp.c new file mode 100644 index 0000000..f82a91c --- /dev/null +++ b/textcomp.c @@ -0,0 +1,126 @@ +/* textcomp.c - compress strings of text to 6 bits per byte. + loosely based on the z-machine's ZSCII compression. + + Example: "Taipan" (7 bytes, including null terminator) encodes as + 0xb8 0x12 0x50 0x04 0xe0 0x00 (6 bytes). + + Longer strings approach 75% compression ratio. + + No encoded string can be over 256 bytes long, as the decompressor + can't currently handle it. + + The alphabet contains only upper/lowercase letters, space, newline, + and some punctuation. In particular, numbers are not supported. + + alphabet: + 0 = end + 1-26 = a-z + 27-52 = A-Z + 53 = space + 54 = ! + 55 = % + 56 = , + 57 = . + 58 = ? + 59 = : + 60 = ' + 61 = ( + 62 = ) + 63 = newline + + All the strings used by taipan.c are listed in the __END__ section + of messages.pl. The perl script calls this program (textcomp) once + per string, and outputs C source consisting of the encoded versions. + Each string in the __END__ section is preceded by a name, and the + generated C source uses these names with M_ prefixed. + + taipan.c calls the function print_msg(const char *) to decode and + print an encoded message. The decoding step slows down printing a bit, + but it's not really noticeable. cputc() is used for printing, so it + respects the reverse video setting (set by rvs_on() and rvs_off()). + + When a newline is printed, the decoder always prints a carriage + return first. Any \r sequences listed in messages.pl are discarded + before encoding is done. + + Actually, no prompts ever use capital X or Z. These should be used for + dictionary lookups. Maybe X is followed by a 3-bit dict ID, for the 8 + most commonly repeated phrases (one of which will of course be "Taipan"), + and Z is a 5- or 6-bit ID for 32 or 64 less common phrases. So far this + isn't implemented because the decompressor isn't reentrant (yet). +*/ + +#include <stdio.h> +#include <stdlib.h> + +unsigned char out[1024]; +int bitcount = 0; + +int getcode(int c) { + if(c >= 'a' && c <= 'z') + return c - 'a' + 1; + if(c >= 'A' && c <= 'Z') + return c - 'A' + 27; + + switch(c) { + case ' ': return 53; + case '!': return 54; + case '%': return 55; + case ',': return 56; + case '.': return 57; + case '?': return 58; + case ':': return 59; + case '\'': return 60; + case '(': return 61; + case ')': return 62; + case '\n': return 63; + case '\r': break; + default: + fprintf(stderr, "unhandled ASCII code %d\n", c); + exit(1); + break; + } +} + +void appendbit(unsigned char b) { + int pos = bitcount / 8; + int bitpos = 7 - (bitcount % 8); + unsigned char val = b << bitpos; + out[pos] |= val; + fprintf(stderr, "%d: appending bit %d at pos %d, bitpos %d, value $%02x\n", bitcount, b, pos, bitpos, val); + bitcount++; +} + +void appendcode(int code) { + int bit; + for(bit = 0x20; bit > 0; bit >>= 1) { + appendbit((code & bit) != 0); + } +} + +int main(int argc, char **argv) { + int c, code, count = 1; /* 1 to account for null terminator */ + + while((c = getchar()) != EOF) { + code = getcode(c); + fprintf(stderr, "c == %d, code == %d\n", c, code); + appendcode(code); + count++; + } + appendcode(0); + + code = 0; + for(c = 0; c < ((bitcount + 7) / 8); c++) { + printf("0x%02x ", out[c]); + code++; + } + + if(code > 256) { + fprintf(stderr, "input too long\n"); + exit(1); + } + + fprintf(stderr, "%d bytes in (added null), %d bytes out, ratio %.2f\n", + count, code, (float)(code)/(float)count); + return 0; +} diff --git a/textdecomp.s b/textdecomp.s new file mode 100644 index 0000000..5d629ba --- /dev/null +++ b/textdecomp.s @@ -0,0 +1,93 @@ + +; text decompressor for taipan. +; text is packed 6 bits per character. see textcomp.c +; for details. + + .include "atari.inc" + .export _print_msg + .import _cputc + + srcptr = FR1 + outbyte = FR0 ; decoded 6-bit byte + bitcount = FR0+1 ; counts 8..1, current bit in inbyte + inbyte = FR0+2 + ysave = FR0+3 + + .rodata +table: ; outbyte values 53..63 + .byte ' ', '!', '%', ',', '.', '?', ':', 39, 40, 41, $9b + tablesize = * - table + + .ifdef CART_TARGET + .segment "HIGHCODE" + .else + .code + .endif + +; extern void __fastcall__ print_msg(char *msg); +_print_msg: + sta srcptr + stx srcptr+1 + lda #0 + sta outbyte + ldy #$ff ; since we increment it first thing... + + ldx #6 ; counts 6..1, current bit in outbyte +@nextbyte: + iny + lda #8 + sta bitcount + lda (srcptr),y + sta inbyte +@bitloop: + asl inbyte + rol outbyte + dex + beq @decode ; got 6 bits + dec bitcount + bne @bitloop + beq @nextbyte + +@decode: + lda outbyte + bne @notend + rts ; 0 = end of message + +@notend: + cmp #27 + bcs @notlower + adc #'a'-1 ; 1-26 are a-z + bne @printit + +@notlower: + cmp #52 + bcs @notupper + adc #38 ; 27-52 are A-Z + bne @printit + +@notupper: + sbc #53 ; 53-63 are table lookups + tax + lda table,x + +@printit: + sty ysave ; _cputc trashes Y + + cmp #$9b ; always print a \r after a \n + bne @nocr + lda #$0d ; \r + jsr _cputc + lda #$9b +@nocr: + jsr _cputc + ldy ysave + lda #0 + sta outbyte + ldx #6 + dec bitcount + beq @nextbyte + bne @bitloop + + decodersize = * - _print_msg + + .out .sprintf("print_msg() is %d bytes", decodersize + tablesize) |