687 lines
26 KiB
Awk
687 lines
26 KiB
Awk
# awlite: POSIX AWK port of Text Elite
|
|
# Version 1.7
|
|
# Original high-level algorithms from Text Elite 1.5 by Ian Bell, 1999, 2015
|
|
# Porting, corrections, improvements 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
|
|
# - galaxy jumps are no longer free and cost 5000 credits each (like in classic Elite and Oolite)
|
|
# - cargo hold expansion also is non-free (400 credits) and can only be done once from 20t to 35t (like in classic Elite)
|
|
# - 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
|
|
# - the "cash" and "sneak" commands are removed since v1.6 (use saves to cheat)
|
|
# - state saving functionality since v1.6 with "save" and "load" commands
|
|
# - since v1.6.1, the game gives you a hint if you might have found Raxxla
|
|
# - since v1.6.3, galaxy names are actually displayed (taken from ArcElite)
|
|
# - since v1.7, "stat" command and basic ranking was introduced
|
|
# ... 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)
|
|
}
|
|
|
|
# ============================ #
|
|
# Game code itself starts here #
|
|
# ============================ #
|
|
|
|
# PRNG part
|
|
|
|
function mysrand(seed) { srand(seed); rng_lastrand = seed - 1 }
|
|
|
|
function myrand(r) {
|
|
if(game["use_native_rand"] > 0) return int(rand() * 65536)
|
|
else { # attempt to optimize McDonnell's generator
|
|
r = (rng_lastrand * 3677 + 3680) % 2147483648
|
|
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"] = 2 + (sinfo["economy"]%2) + (sinfo["economy"]>3?4:0)
|
|
ecof = 7 - sinfo["economy"]
|
|
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("", plannames) # global galaxy planet 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
|
|
plannames[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]
|
|
player["expense"] += 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
|
|
player["jumps"]++
|
|
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
|
|
if(match(sinfo["name"], /RA..LA/)) # found Raxxla?
|
|
printf("\n%s", "Wait a sec... Is this the legendary Raxxla?\nWe'll never know for sure...")
|
|
}
|
|
}
|
|
|
|
# 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, plannames[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
|
|
function dotweakrand() { game["use_native_rand"] = 1 - game["use_native_rand"] }
|
|
|
|
# local command implementation
|
|
function dolocal(d, i, p, si) {
|
|
printf("\nGalaxy %i - %s\n", player["galaxynum"], galnames[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
|
|
}
|
|
|
|
# jump to next galaxy (planet number is preserved)
|
|
function dogalhyp() {
|
|
if(player["cash"] > game["galhypcost"]) {
|
|
player["cash"] -= game["galhypcost"]
|
|
player["expense"] += game["galhypcost"]
|
|
player["galaxynum"]++
|
|
player["jumps"]++
|
|
if(player["galaxynum"] == 9) player["galaxynum"] = 1
|
|
buildgalaxy(player["galaxynum"], globalseeds) # build a new galaxy
|
|
}
|
|
else printf("Not enough credits for hyperspace jump!\nMust have at least %.1f CR", game["galhypcost"]/10)
|
|
}
|
|
|
|
# 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) {
|
|
if(player["holdspace"] >= game["cargoexpsize"]) {
|
|
printf("\nExpansion not possible! The cargo bay already is at maximum capacity")
|
|
return 0
|
|
}
|
|
if(player["cash"] < game["cargoexpcost"]) {
|
|
printf("\nNot enough cash! Need %.1f CR for upgrading the cargo bay", game["cargoexpcost"]/10)
|
|
return 0
|
|
}
|
|
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
|
|
player["cash"] -= game["cargoexpcost"]
|
|
player["expense"] += game["cargoexpcost"]
|
|
printf("\nCargo bay expanded to %dt", game["cargoexpsize"])
|
|
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, unitnames[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, unitnames[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"]
|
|
player["expense"] += 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
|
|
}
|
|
|
|
# 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 product amount")
|
|
printf("\nSell product amount")
|
|
printf("\nFuel amount (buy amount LY of fuel)")
|
|
printf("\nJump planetname (limited by fuel)")
|
|
printf("\nGalhyp (jump to next galaxy)")
|
|
printf("\nInfo planetname (print info on system)")
|
|
printf("\nMkt (show market prices)")
|
|
printf("\nLocal (list systems within 7 lightyears)")
|
|
printf("\nHold (expand cargo bay to %dt)", game["cargoexpsize"])
|
|
printf("\nStat (show player statistics)")
|
|
printf("\nSave playername (save game into current working directory)")
|
|
printf("\nLoad playername (load game from current working directory)")
|
|
printf("\nQuit or ^D (exit)")
|
|
printf("\nHelp (display this text)")
|
|
printf("\nRand (toggle RNG)")
|
|
printf("\n\nAbbreviations allowed eg. b fo 5 = Buy Food 5, m = Mkt")
|
|
}
|
|
|
|
# Save/load functionality
|
|
|
|
function dosave(savename, fs, fn) {
|
|
gsub(/[^[:alnum:]]/, "_", savename) # sanitize all non-alnum chars
|
|
player["cargo"] = assocser(shipshold, "@")
|
|
fs = assocser(player, "|")
|
|
delete player["cargo"]
|
|
fn = savename ".awlite"
|
|
printf("%s\n", fs) > fn # write the savefile
|
|
close(fn)
|
|
printf("\nGame saved in %s", fn)
|
|
}
|
|
|
|
function doload(savename, fn, fs) {
|
|
gsub(/[^[:alnum:]]/, "_", savename) # sanitize all non-alnum chars
|
|
fn = savename ".awlite"
|
|
if((getline fs < fn) > 0) { # read the savefile
|
|
split("", player) # clear the player array
|
|
split("", shipshold) # clear the shipshold array
|
|
assocdes(fs, player, "|")
|
|
assocdes(player["cargo"], shipshold, "@")
|
|
delete player["cargo"]
|
|
split("", globalseeds) # init galaxy seeds
|
|
buildgalaxy(player["galaxynum"], globalseeds) # build the current galaxy
|
|
genmarket(0, economies[player["currentplanet"]]) # build local market
|
|
printf("\nGame loaded from %s", fn)
|
|
} else printf("\nError reading the savefile!")
|
|
close(fn)
|
|
}
|
|
|
|
# player statistics and ranking display
|
|
# ranking formula might be subject to change in future versions
|
|
function dostat(profind, rank) {
|
|
profind = 0 # profit margin index
|
|
rank = 0
|
|
if(player["expense"] > 0) {
|
|
profind = (player["cash"]-1000) / player["expense"]
|
|
if(profind > 1) rank = int(log(profind) / log(2)) + 1 # log base 2
|
|
if(rank < 0) rank = 0
|
|
if(rank > 8) rank = 8
|
|
}
|
|
printf("\nRank: %s", ranknames[rank])
|
|
printf("\n\n========= Money =========")
|
|
printf("\nBalance %17s", sprintf("%.1f CR",player["cash"]/10))
|
|
printf("\nExpenses %16s", sprintf("%.1f CR", player["expense"]/10))
|
|
printf("\nProfit margin %11s", sprintf("%.2f%%", profind*100))
|
|
printf("\n\n======= Ship info =======")
|
|
printf("\nFuel %20s", sprintf("%.1f LY", player["fuel"]/10))
|
|
printf("\nCargo space %13s", sprintf("%ut", player["holdspace"]))
|
|
printf("\nJumps %19s", sprintf("%u", player["jumps"]))
|
|
}
|
|
|
|
# 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["galhypcost"] = 50000 # 5000 CR
|
|
game["cargoexpcost"] = 4000 # 400 CR for one-time upgrade
|
|
game["cargoexpsize"] = 35 # 35t after the upgrade
|
|
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 (100 CR)
|
|
player["expense"] = 0 # for tracking overall expenses
|
|
player["jumps"] = 0 # for counting interplanetary jumps
|
|
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, " ")
|
|
|
|
# galaxy names (1-indexed)
|
|
split("Santaari Colesque Lara'tan Angiana Proximus Sol Jaftra Xrata", galnames, " ")
|
|
|
|
# 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, ",")
|
|
|
|
# rank names
|
|
asplit("Penniless,Mostly Penniless,Peddler,Dealer,Merchant,Broker,Entrepreneur,Tycoon,Elite", ranknames, ",")
|
|
|
|
# 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.7\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(cmd == "st" || cmd == "stat") dostat()
|
|
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 == "hold") dohold(game["cargoexpsize"])
|
|
else if(action == "save") dosave(paramstr)
|
|
else if(action == "load") doload(paramstr)
|
|
else printf("Unknown command")
|
|
printf("\n\nCash: %.1f> ", player["cash"]/10)
|
|
}
|
|
print "\nBye!"
|
|
}
|