Files
awlite/awlite.awk
T

630 lines
22 KiB
Awk
Raw Normal View History

2024-01-21 19:35:11 +02:00
# awlite: POSIX AWK port of Text Elite 1.5
# Version 1.5.1-alpha
# Original C version by Ian Bell, 1999, 2015
# Porting, corrections and optimizations by Luxferre, 2024
#
# Tested on: nawk/one-true-awk, busybox awk, gawk --posix, mawk -W posix
# Should run on any current POSIX-compliant AWK implementation but
# must be run with LC_ALL=C environment variable to work correctly!
#
# Gameplay differences from the original C version of TE 1.5:
# - multiple typos corrected in text strings
# - the "cash" and "sneak" commands are only available to the REPL if running with -v CHEAT=1
# - alien items are available by default, can be overridden with -v NO_ALIEN_ITEMS=1
# - economy names are no longer shortened
# - the "politically correct" goods names are turned on with -v CENSORED=1
# - the following goods have been renamed: "Robot Slaves" to "Robots", "Liquor/Wines" to "Liquors", "Gem-Strones" to "Gem-stones"
# - market and local info tables are better aligned
# ... to be continued ...
# utility functions
# determine (ordered) array length
function alen(a, i, k) {
k = 0
for(i in a) k++
return k
}
# split a string with separator into an array but with 0-based indexes
function asplit(s, a, sep, len, i) {
split(s, a, sep) # get 1-based-index array in a
len = alen(a)
for(i=0;i<len;i++) a[i] = a[i+1] # move everything to the left
delete a[len] # delete the last element after moving
}
# serialize any associative array into a string
# sep must be a single char not occurring in any key or value
function assocser(aa, sep, outs, k) {
outs = "" # initialize an ordered array string
for(k in aa) # iterate over keys
outs = outs sep k sep aa[k]
return substr(outs, 2) # delete the first sep
}
# deserialize any associative array from a string
# sep must be a single char used when calling assocser() function
function assocdes(s, aa, sep, oa, i, len) {
split("", aa) # erase aa array
split(s, oa, sep) # get 1-based ordered array in oa
len = alen(oa) # ordered array length
for(i=1;i<=len;i+=2) # populate aa
aa[oa[i]] = oa[i+1]
}
# get the ASCII code of a character
# usage: ord(c) => integer
function ord(c, b) {
# init char-to-ASCII mapping if it's not there yet
if(!TGL_ORD["#"]) for(b=0;b<256;b++) TGL_ORD[sprintf("%c", b)] = b
return int(TGL_ORD[c])
}
# Required bitwise operations (as POSIX AWK doesn't support them)
function bw_and(a, b, v, r) {
v = 1; r = 0
while(a > 0 || b > 0) {
if((a%2) == 1 && (b%2) == 1) r += v
a = int(a/2)
b = int(b/2)
v *= 2
}
return int(r)
}
function bw_or(a, b, v, r) {
v = 1; r = 0
while(a > 0 || b > 0) {
if((a%2) == 1 || (b%2) == 1) r += v
a = int(a/2)
b = int(b/2)
v *= 2
}
return int(r)
}
function bw_xor(a, b, v, r) {
v = 1; r = 0
while(a > 0 || b > 0) {
if((a%2) != (b%2)) r += v
a = int(a/2)
b = int(b/2)
v *= 2
}
return int(r)
}
# ============================ #
# Game code itself starts here #
# ============================ #
# PRNG part
2024-01-21 20:10:33 +02:00
function mysrand(seed) { srand(seed); rng_lastrand = seed - 1 }
2024-01-21 19:35:11 +02:00
function myrand(r) {
if(game["use_native_rand"] > 0) return int(rand() * 65536)
else { # attempt to optimize McDonnell's generator
2024-01-21 19:38:23 +02:00
r = (rng_lastrand * 3677 + 3680) % 2147483648
2024-01-21 19:35:11 +02:00
rng_lastrand = r -1
return r
}
}
function randbyte() {return myrand()%256}
# other functions
function mymin(a,b) {return (a < b) ? a : b}
# distance between 2 planets
function distance(p1x, p1y, p2x, p2y, dx, dy) {
dx = p1x - p2x
dy = p1y - p2y
return int(0.5 + 4*sqrt(dx*dx + dy*dy/4))
}
function rotl(x) { # rotate left 1 bit mod 256
x = x % 256 # truncate to a byte first
return (x * 2 + ((x > 127) ? 1 : 0)) % 256
}
function twist(x) { # twister function
return (256 * rotl(int(x/256)) + rotl(x%256)) % 65536
}
function galswitch(seeds) { # galaxy switcher (accepts an array)
seeds[0] = twist(seeds[0])
seeds[1] = twist(seeds[1])
seeds[2] = twist(seeds[2])
}
function tweakseed(seeds, t) { # another seed tweaker
t = (seeds[0] + seeds[1] + seeds[2]) % 65536
seeds[0] = seeds[1]
seeds[1] = seeds[2]
seeds[2] = t
}
# Generate system info from seed
# populates the sinfo map
function makesystem(seeds, sinfo, p1, p2, p3, p4, lnf, ecof, sname) {
lnf = bw_and(seeds[0], 64)
sinfo["x"] = int(seeds[1] / 256)
sinfo["y"] = int(seeds[0] / 256)
sinfo["govtype"] = int(seeds[1] / 8) % 8
sinfo["economy"] = int(seeds[0] / 256) % 8
if(sinfo["govtype"] <= 1) sinfo["economy"] = bw_or(sinfo["economy"], 2)
ecof = bw_xor(sinfo["economy"], 7)
sinfo["techlev"] = (sinfo["x"] % 4) + ecof + int(sinfo["govtype"] / 2)
if((sinfo["govtype"] % 2) == 1) sinfo["techlev"]++
sinfo["population"] = 4 * (sinfo["techlev"]) + sinfo["economy"] + sinfo["govtype"] + 1
sinfo["productivity"] = ((ecof + 3) * (sinfo["govtype"] + 4)) * sinfo["population"] * 8
sinfo["radius"] = 256 * ((int(seeds[2] / 256) % 16) + 11) + sinfo["x"]
# goat soup seed parts
sinfo["gsseed_a"] = seeds[1] % 256
sinfo["gsseed_b"] = int(seeds[1] / 256) % 256
sinfo["gsseed_c"] = seeds[2] % 256
sinfo["gsseed_d"] = int(seeds[2] / 256) % 256
# name pair indexes
p1 = 2 * (int(seeds[2] / 256) % 32); tweakseed(seeds)
p2 = 2 * (int(seeds[2] / 256) % 32); tweakseed(seeds)
p3 = 2 * (int(seeds[2] / 256) % 32); tweakseed(seeds)
p4 = 2 * (int(seeds[2] / 256) % 32); tweakseed(seeds)
sname = pairs[p1] pairs[p1+1] pairs[p2] pairs[p2+1] pairs[p3] pairs[p3+1]
if(lnf) sname = sname pairs[p4] pairs[p4+1]
gsub(/\./, "", sname) # remove all dots from sname
sinfo["name"] = sname # write the final name variant
# return sinfo
}
# "Goat Soup" planetary description string code
function gs_rnd(sinfo, a, x) { # accepts system info to modify gsseed
x = (sinfo["gsseed_a"] * 2) % 256
a = x + sinfo["gsseed_c"]
if(sinfo["gsseed_a"] > 127) a++
sinfo["gsseed_a"] = a % 256
sinfo["gsseed_c"] = x
x = sinfo["gsseed_b"]
a = (int(a / 256) + x + sinfo["gsseed_d"]) % 256
sinfo["gsseed_b"] = a
sinfo["gsseed_d"] = x
return a
}
# main desc generator, recursive, modifies sinfo as well
function goat_soup(source, sinfo, l, c, i, j, k, v, rnd, dsel) {
l = length(source)
for(i=0;i<l;i++) {
c = ord(substr(source, i+1, 1))
if(c < 128) printf("%c", c)
else {
if(c <= 164) {
rnd = gs_rnd(sinfo)
asplit(desc_list[c - 129], dsel, ",") # select the string from list
j = ((rnd >= 51) ? 1 : 0) + ((rnd >= 102) ? 1 : 0)
j += ((rnd >= 153) ? 1 : 0) + ((rnd >= 204) ? 1 : 0)
goat_soup(dsel[j], sinfo)
} else {
if(c == 176) { # planet name
v = sinfo["name"]
v = substr(v, 1, 1) tolower(substr(v, 2))
printf("%s", v)
} else if(c == 177) { # planet name + ian
v = sinfo["name"]
v = substr(v, 1, 1) tolower(substr(v, 2))
# find last "e" or "i" occurrence in v
j = match(v, /[eia]+$/)
if(j == 0) j = length(v) + 1
printf("%sian", substr(v, 1, j - 1))
} else if(c == 178) { # random name
v = gs_rnd(sinfo) % 4
for(j = 0; j <= v; j++) {
k = bw_and(62, gs_rnd(sinfo))
printf("%c", (j > 0) ? tolower(pairs0[k]) : pairs0[k])
printf("%c", tolower(pairs0[k+1]))
}
} else { printf("<bad char in data [%X]>",c); return }
}
}
}
}
# Galaxy builder (populates seeds array and global galaxy arrays)
function buildgalaxy(gnum, seeds, si, i) {
asplit("23114 584 46931", seeds, " ")
for(i=1;i<gnum;i++) galswitch(seeds)
split("", galaxy) # global galaxy array
split("", galnames) # global galaxy names array
split("", economies) # economy mapping
for(i=0;i<galsize;i++) {
split("", si) # init a new system info array
makesystem(seeds, si) # populate it
galaxy[i] = assocser(si, "|") # serialize into the field
galnames[i] = si["name"] # populate the name
galcoords_x[i] = si["x"] # populate x coordinate
galcoords_y[i] = si["y"] # populate y coordinate
economies[i] = si["economy"] # populate economy type
}
}
# Market functions
# buy amount a of product i, return amount bought
function gamebuy(i, a, t) {
if(player["cash"] < 0) t = 0
else {
t = mymin(localmarket_quantity[i], a)
if(goods_units[i] == 0) t = mymin(player["holdspace"], t)
t = mymin(t, int(player["cash"] / localmarket_price[i]))
}
shipshold[i] = int(shipshold[i]) + t
localmarket_quantity[i] -= t
player["cash"] -= t * localmarket_price[i]
if(goods_units[i] == 0) player["holdspace"] -= t
return t
}
# sell amount a of product i, return amount sold
function gamesell(i, a, t) {
t = mymin(shipshold[i], a)
shipshold[i] -= t
localmarket_quantity[i] += t
if(goods_units[i] == 0) player["holdspace"] += t
player["cash"] += t * localmarket_price[i]
return t
}
# generate market for a particular planetary system
# accepts fluctuation byte and economy type number
# recreates localmarket_quantity and localmarket_price arrays
function genmarket(fluct, econtype, i, q, product, changing) {
for(i=0;i<=IDX_ALIEN_ITEMS;i++) {
product = econtype * goods_grads[i]
changing = bw_and(fluct, goods_masks[i])
q = (goods_bquants[i] + changing - product + 256) % 256
if(q > 127) q = 0
localmarket_quantity[i] = q % 64
q = (goods_bprices[i] + changing + product) % 256
localmarket_price[i] = q * 4
}
if(NO_ALIEN_ITEMS) localmarket_quantity[IDX_ALIEN_ITEMS] = 0
}
# display local market from localmarket_quantity and localmarket_price
function displaymarket(i) {
for(i=0;i<=IDX_ALIEN_ITEMS;i++) {
printf("\n%-16s", goods_names[i])
printf("%-5s", sprintf("%.1f", localmarket_price[i]/10))
printf("\t%u%s", localmarket_quantity[i], unitnames[goods_units[i]])
printf("\t\t%u", shipshold[i])
}
}
# move to system i
function gamejump(i, si) {
player["currentplanet"] = i
assocdes(galaxy[i], si, "|")
genmarket(randbyte(), int(si["economy"]))
}
# print data for given system
function prisys(sinfo, compressed) {
if(compressed) {
printf("%10s TL: %2i ", sinfo["name"], sinfo["techlev"] + 1)
printf("%-20s %-15s", econnames[sinfo["economy"]], govnames[sinfo["govtype"]])
} else {
printf("\nSystem: %s", sinfo["name"])
printf("\nPosition (%i, %i)", sinfo["x"], sinfo["y"])
printf("\nEconomy: (%i) %s", sinfo["economy"], econnames[sinfo["economy"]])
printf("\nGovernment: (%i) %s", sinfo["govtype"], govnames[sinfo["govtype"]])
printf("\nTech level: %2i", sinfo["techlev"] + 1)
printf("\nTurnover: %u", sinfo["productivity"])
printf("\nRadius: %u", sinfo["radius"])
printf("\nPopulation: %u billion\n", int(sinfo["population"]/8))
goat_soup("\217 is \227.", sinfo) # generate and print the description
}
}
# return id of the planet whose name matches passed string
# closest to current planet - if none, return current planet
function matchsys(s, d, i, p, cd) {
p = player["currentplanet"]
d = 9999
s = toupper(s) # system names are stored in uppercase
for(i=0;i<galsize;i++) {
if(index(s, galnames[i]) == 1) { # found i-th system
cd = distance(galcoords_x[i], galcoords_y[i], galcoords_x[p], galcoords_y[p])
if(cd < d) {d = cd; p = i}
}
}
return p
}
# direct command implementations (may be further merged into the REPL directly)
# rand command implementation
2024-01-21 20:10:33 +02:00
function dotweakrand() { game["use_native_rand"] = 1 - game["use_native_rand"] }
2024-01-21 19:35:11 +02:00
# local command implementation
function dolocal(d, i, p, si) {
printf("Galaxy number %i", player["galaxynum"])
p = int(player["currentplanet"])
for(i=0;i<galsize;i++) {
d = distance(galcoords_x[i], galcoords_y[i], galcoords_x[p], galcoords_y[p])
if(d <= game["maxfuel"]) {
printf("\n %s ", (d <= player["fuel"]) ? "*" : "-")
assocdes(galaxy[i], si, "|") # deserialize current system
prisys(si, 1)
printf(" (%.1f LY)", d/10)
}
}
}
# jump to planet name s
function dojump(s, dest, d, p, si) {
dest = matchsys(s) # find the destination
p = int(player["currentplanet"])
if(dest == p) { printf("\nBad jump"); return 0}
d = distance(galcoords_x[dest], galcoords_y[dest], galcoords_x[p], galcoords_y[p])
if(d > player["fuel"]) {printf("\nJump too far"); return 0}
player["fuel"] -= d
gamejump(dest, si)
prisys(si, 0)
return 1
}
# dojump without fuel expense
function dosneak(s, kp, r) {
kp = player["fuel"]
player["fuel"] = 666
r = dojump(s)
player["fuel"] = kp
return r
}
# jump to next galaxy (planet number is preserved)
function dogalhyp() {
player["galaxynum"]++
if(player["galaxynum"] == 9) player["galaxynum"] = 1
buildgalaxy(player["galaxynum"], globalseeds) # build a new galaxy
}
# print planet info
function doinfo(s, dest, si) {
dest = matchsys(s) # find the system
assocdes(galaxy[dest], si, "|") # deserialize found system
prisys(si, 0) # print its info
}
# hold command implementation
function dohold(a, t, i) {
t = 0
a = int(a)
for(i=0;i<=IDX_ALIEN_ITEMS;i++)
if(goods_units[i] == 0) t += shipshold[i]
if(t > a) {printf("\nHold too full"); return 0}
player["holdspace"] = a - t
return 1
}
# check string s against n options in array a
# if matches ith element return i+1 else return 0
function stringmatch(s, a, n, i) {
s = tolower(s)
for(i=0;i<n;i++)
if(index(tolower(a[i]), s) == 1) return i+1
return 0
}
# sell command implementation (accepts space-separated name and amount)
function dosell(s, sp, pname, pquant, i, t) {
split(s, sp, " ")
pname = sp[1]
pquant = int(sp[2])
if(pquant < 1) pquant = 1
i = stringmatch(pname, goods_names, IDX_ALIEN_ITEMS + 1)
if(i == 0) {printf("\nUnknown product"); return 0}
i -= 1 # switch to the real product index
t = gamesell(i, pquant)
pname = goods_names[i] # update real product name
if(t > 0) {
printf("\nSelling %i%s of %s", t, goods_units[i], pname)
} else printf("\nCannot sell any %s", pname)
return 1
}
# buy command implementation (accepts space-separated name and amount)
function dobuy(s, sp, pname, pquant, i, t) {
split(s, sp, " ")
pname = sp[1]
pquant = int(sp[2])
if(pquant < 1) pquant = 1
i = stringmatch(pname, goods_names, IDX_ALIEN_ITEMS + 1)
if(i == 0) {printf("\nUnknown product"); return 0}
i -= 1 # switch to the real product index
t = gamebuy(i, pquant)
pname = goods_names[i] # update real product name
if(t > 0) {
printf("\nBuying %i%s of %s", t, goods_units[i], pname)
} else printf("\nCannot buy any %s", pname)
return 1
}
# attempt to buy f tonnes of fuel
function gamefuel(f) {
if((f + player["fuel"]) > game["maxfuel"])
f = game["maxfuel"] - player["fuel"]
if(game["fuelcost"] > 0 && (f * game["fuelcost"] > player["cash"]))
f = int(player["cash"] / game["fuelcost"])
player["fuel"] += f
player["cash"] -= f * game["fuelcost"]
return f
}
# fuel command implementation
function dofuel(f) {
f = gamefuel(int(10 * f))
if(f == 0) printf("\nCan't buy any fuel")
else printf("\nBuying %.1fLY fuel", f/10)
return 1
}
# (cheat) alter cash command implementation
function docash(s) {
player["cash"] += int(10 * s)
if(player["cash"] < 0) player["cash"] = 0
}
# show stock market
function domkt() {
displaymarket()
printf("\n\nFuel: %.1f\nHoldspace: %it", player["fuel"]/10, player["holdspace"])
}
# display help
function dohelp() {
printf("\nCommands are:");
printf("\nBuy tradegood amount");
printf("\nSell tradegood amount");
printf("\nFuel amount (buy amount LY of fuel)");
printf("\nJump planetname (limited by fuel)");
if(CHEAT)
printf("\nSneak planetname (any distance - no fuel cost)");
printf("\nGalhyp (jumps to next galaxy)");
printf("\nInfo planetname (prints info on system)");
printf("\nMkt (shows market prices)");
printf("\nLocal (lists systems within 7 light years)");
if(CHEAT)
printf("\nCash number (alters cash - cheating!)");
printf("\nHold number (change cargo bay)");
printf("\nQuit or ^C (exit)");
printf("\nHelp (display this text)");
printf("\nRand (toggle RNG)");
printf("\n\nAbbreviations allowed eg. b fo 5 = Buy Food 5, m= Mkt");
}
# Game init procedure: first thing to call in the BEGIN block
function gameinit() {
rng_lastrand = 0 # state for custom PRNG
mysrand(12345); # ensure repeatability
numForLave = 7 # Lave is the 7th planet in galaxy 1
split("",game) # overall game state is stored here
game["use_native_rand"] = 1
game["fuelcost"] = 2 # 0.2 CR/lightyear
game["maxfuel"] = 70 # 7.0 LY tank
split("",player) # current (saveable) player state is stored here
player["currentplanet"] = numForLave # current planet (1 to 256)
player["galaxynum"] = 1 # current galaxy (1 to 8)
player["cash"] = 1000 # current cash
player["fuel"] = game["maxfuel"] # current fuel amount
player["holdspace"] = 20 # max cargo hold space
split("",shipshold) # (saveable) contents of cargo bay, up to 16 items
# constants and tables
# unit names
asplit("t kg g", unitnames, " ")
# government names
asplit("Anarchy,Feudal,Multi-gov,Dictatorship,Communist,Confederacy,Democracy,Corporate State", govnames, ",")
# economy names
asplit("Rich Industrial,Average Industrial,Poor Industrial,Mainly Industrial,Mainly Agricultural,Rich Agricultural,Average Agricultural,Poor Agricultural", econnames, ",")
# Goods
# Data for DB's price/availability generation system:
# Base price, Gradient, Base quantity, Mask, Unit, Name
split("", commodities) # will split on demand
commodities[0] = "19,-2,6,1,0,Food"
commodities[1] = "20,-1,10,3,0,Textiles"
commodities[2] = "65,-3,2,7,0,Radioactives"
commodities[3] = "40,-5,226,31,0," (CENSORED ? "Robots" : "Slaves")
commodities[4] = "83,-5,251,15,0," (CENSORED ? "Beverages" : "Liquors")
commodities[5] = "196,8,54,3,0,Luxuries"
commodities[6] = "235,29,8,120,0," (CENSORED ? "Rare Species" : "Narcotics")
commodities[7] = "154,14,56,3,0,Computers"
commodities[8] = "117,6,40,7,0,Machinery"
commodities[9] = "78,1,17,31,0,Alloys"
commodities[10] = "124,13,29,7,0,Firearms"
commodities[11] = "176,-9,220,63,0,Furs"
commodities[12] = "32,-1,53,3,0,Minerals"
commodities[13] = "97,-1,66,7,1,Gold"
commodities[14] = "171,-2,55,31,1,Platinum"
commodities[15] = "45,-1,250,15,2,Gem-stones"
commodities[16] = "53,15,192,7,0,Alien Items"
IDX_ALIEN_ITEMS=16
split("", goods_bprices) # holds base prices
split("", goods_grads) # holds gradients
split("", goods_bquants) # holds base quantities
split("", goods_masks) # holds masks
split("", goods_units) # holds measurement units
split("", goods_names) # holds goods names
for(i in commodities) { # it's pre-ordered anyway
split(commodities[i], parts, ",") # we can use 1-based here
goods_bprices[i] = int(parts[1])
goods_grads[i] = int(parts[2])
goods_bquants[i] = int(parts[3])
goods_masks[i] = int(parts[4])
goods_units[i] = int(parts[5])
goods_names[i] = parts[6]
}
# localmarket assoc arrays
split("", localmarket_quantity)
split("", localmarket_price)
# digrams for planet names
asplit("ABOUSEITILETSTONLONUTHNOALLEXEGEZACEBISOUSESARMAINDIREA.ERATENBERALAVETIEDORQUANTEISRION", pairs0, "")
asplit("..LEXEGEZACEBISOUSESARMAINDIREA.ERATENBERALAVETIEDORQUANTEISRION", pairs, "")
# planet description string parts
desc_list_str = "fabled,notable,well known,famous,noted|very,mildly,most,reasonably,|ancient,\225,great,vast,pink|\236 \235 plantations,mountains,\234,\224 forests,oceans|shyness,silliness,mating traditions,loathing of \206,love for \206|food blenders,tourists,poetry,discos,\216|talking tree,crab,bat,lobst,\262|beset,plagued,ravaged,cursed,scourged|\226 civil war,\233 \230 \231s,a \233 disease,\226 earthquakes,\226 solar activity|its \203 \204,the \261 \230 \231,its inhabitants' \232 \205,\241,its \215 \216|juice,brandy,water,brew,gargle blasters|\262,\261 \231,\261 \262,\261 \233,\233 \262|fabulous,exotic,hoopy,unusual,exciting|cuisine,night life,casinos,sit coms, \241 |\260,The planet \260,The world \260,This planet,This world|n unremarkable, boring, dull, tedious, revolting|planet,world,place,little planet,dump|wasp,moth,grub,ant,\262|poet,arts graduate,yak,snail,slug|tropical,dense,rain,impenetrable,exuberant|funny,weird,unusual,strange,peculiar|frequent,occasional,unpredictable,dreadful,deadly|\202 \201 for \212,\202 \201 for \212 and \212,\210 by \211,\202 \201 for \212 but \210 by \211,a\220 \221|\233,mountain,edible,tree,spotted|\237,\240,\207oid,\223,\222|ancient,exceptional,eccentric,ingrained,\225|killer,deadly,evil,lethal,vicious|parking meters,dust clouds,ice bergs,rock formations,volcanoes|plant,tulip,banana,corn,\262weed|\262,\261 \262,\261 \233,inhabitant,\261 \262|shrew,beast,bison,snake,wolf|leopard,cat,monkey,goat,fish|\214 \213,\261 \237 \242,its \215 \240 \242,\243 \244,\214 \213|meat,cutlet,steak,burgers,soup|ice,mud,Zero-G,vacuum,\261 ultra|hockey,cricket,karate,polo,tennis"
asplit(desc_list_str, desc_list, "|")
galsize = 256 # number of systems in one galaxy
}
# main code block
BEGIN {
gameinit() # init everything
split("", globalseeds) # init galaxy seeds
buildgalaxy(player["galaxynum"], globalseeds) # build the current galaxy
genmarket(0, economies[player["currentplanet"]]) # build local market
printf("\nWelcome to awlite 1.5.1 (based on Text Elite 1.5)\n")
dohelp()
# start the REPL
printf("\n\nCash: %.1f> ", player["cash"]/10)
while((getline cmd) > 0) {
cmd = tolower(cmd) # accept both uppercase and lowercase
spi = index(cmd, " ") # first whitespace in cmd
action = (spi == 0) ? cmd : substr(cmd, 1, spi - 1)
paramstr = (spi == 0) ? "" : substr(cmd, spi+1)
if(cmd == "q" || cmd == "quit") break
else if(cmd == "h" || cmd == "help") dohelp()
else if(cmd == "r" || cmd == "rand") dotweakrand()
else if(cmd == "m" || cmd == "mkt") domkt()
else if(cmd == "l" || cmd == "local") dolocal()
else if(cmd == "g" || cmd == "galhyp") dogalhyp()
else if(action == "i" || action == "info") doinfo(paramstr)
else if(action == "b" || action == "buy") dobuy(paramstr)
else if(action == "s" || action == "sell") dosell(paramstr)
else if(action == "j" || action == "jump") dojump(paramstr)
else if(action == "f" || action == "fuel") dofuel(paramstr)
else if(action == "ho" || action == "hold") dofuel(paramstr)
else if(CHEAT && action == "cash") docash(paramstr)
else if(CHEAT && action == "sneak") dosneak(paramstr)
else printf("Unknown command")
printf("\n\nCash: %.1f> ", player["cash"]/10)
}
print "\nBye!"
}