awlite.awk (27333B)
1 # awlite: POSIX AWK port of Text Elite 2 # Version 1.8.1 3 # Original high-level algorithms from Text Elite 1.5 by Ian Bell, 1999, 2015 4 # Porting, corrections, improvements and optimizations by Luxferre, 2024 5 # 6 # Tested on: nawk/one-true-awk, busybox awk, gawk --posix, mawk -W posix 7 # Should run on any current POSIX-compliant AWK implementation but 8 # must be run with LC_ALL=C environment variable to work correctly! 9 # 10 # Gameplay differences from the original C version of TE 1.5: 11 # - multiple typos corrected in text strings 12 # - galaxy jumps are no longer free and cost 5000 credits each (like in classic Elite and Oolite) 13 # - cargo hold expansion also is non-free and (since v1.8) multi-tiered 14 # - alien items are available by default, can be overridden with -v NO_ALIEN_ITEMS=1 15 # - economy names are no longer shortened 16 # - the "politically correct" goods names are turned on with -v CENSORED=1 17 # - the following goods have been renamed: "Robot Slaves" to "Robots", "Liquor/Wines" to "Liquors", "Gem-Strones" to "Gem-stones" 18 # - market and local info tables are better aligned 19 # - the "cash" and "sneak" commands are removed since v1.6 (use saves to cheat) 20 # - state saving functionality since v1.6 with "save" and "load" commands 21 # - since v1.6.1, the game gives you a hint if you might have found Raxxla 22 # - since v1.6.3, galaxy names are actually displayed (taken from ArcElite) 23 # - since v1.7, "stat" command and basic ranking was introduced 24 # - since v1.8, "hold" command was replaced with "upgrade" with several ships 25 # ... to be continued ... 26 27 # utility functions 28 29 # determine (ordered) array length 30 function alen(a, i, k) { 31 k = 0 32 for(i in a) k++ 33 return k 34 } 35 36 # split a string with separator into an array but with 0-based indexes 37 function asplit(s, a, sep, len, i) { 38 split(s, a, sep) # get 1-based-index array in a 39 len = alen(a) 40 for(i=0;i<len;i++) a[i] = a[i+1] # move everything to the left 41 delete a[len] # delete the last element after moving 42 } 43 44 # serialize any associative array into a string 45 # sep must be a single char not occurring in any key or value 46 function assocser(aa, sep, outs, k) { 47 outs = "" # initialize an ordered array string 48 for(k in aa) # iterate over keys 49 outs = outs sep k sep aa[k] 50 return substr(outs, 2) # delete the first sep 51 } 52 53 # deserialize any associative array from a string 54 # sep must be a single char used when calling assocser() function 55 function assocdes(s, aa, sep, oa, i, len) { 56 split("", aa) # erase aa array 57 split(s, oa, sep) # get 1-based ordered array in oa 58 len = alen(oa) # ordered array length 59 for(i=1;i<=len;i+=2) # populate aa 60 aa[oa[i]] = oa[i+1] 61 } 62 63 # get the ASCII code of a character 64 # usage: ord(c) => integer 65 function ord(c, b) { 66 # init char-to-ASCII mapping if it's not there yet 67 if(!TGL_ORD["#"]) for(b=0;b<256;b++) TGL_ORD[sprintf("%c", b)] = b 68 return int(TGL_ORD[c]) 69 } 70 71 # Required bitwise operations (as POSIX AWK doesn't support them) 72 73 function bw_and(a, b, v, r) { 74 v = 1; r = 0 75 while(a > 0 || b > 0) { 76 if((a%2) == 1 && (b%2) == 1) r += v 77 a = int(a/2) 78 b = int(b/2) 79 v *= 2 80 } 81 return int(r) 82 } 83 84 # ============================ # 85 # Game code itself starts here # 86 # ============================ # 87 88 # PRNG part 89 90 function mysrand(seed) { srand(seed); rng_lastrand = seed - 1 } 91 92 function myrand(r) { 93 if(game["use_native_rand"] > 0) return int(rand() * 65536) 94 else { # attempt to optimize McDonnell's generator 95 r = (rng_lastrand * 3677 + 3680) % 2147483648 96 rng_lastrand = r -1 97 return r 98 } 99 } 100 101 function randbyte() {return myrand()%256} 102 103 # other functions 104 105 function mymin(a,b) {return (a < b) ? a : b} 106 107 # distance between 2 planets 108 function distance(p1x, p1y, p2x, p2y, dx, dy) { 109 dx = p1x - p2x 110 dy = p1y - p2y 111 return int(0.5 + 4*sqrt(dx*dx + dy*dy/4)) 112 } 113 114 function rotl(x) { # rotate left 1 bit mod 256 115 x = x % 256 # truncate to a byte first 116 return (x * 2 + ((x > 127) ? 1 : 0)) % 256 117 } 118 119 function twist(x) { # twister function 120 return (256 * rotl(int(x/256)) + rotl(x%256)) % 65536 121 } 122 123 function galswitch(seeds) { # galaxy switcher (accepts an array) 124 seeds[0] = twist(seeds[0]) 125 seeds[1] = twist(seeds[1]) 126 seeds[2] = twist(seeds[2]) 127 } 128 129 function tweakseed(seeds, t) { # another seed tweaker 130 t = (seeds[0] + seeds[1] + seeds[2]) % 65536 131 seeds[0] = seeds[1] 132 seeds[1] = seeds[2] 133 seeds[2] = t 134 } 135 136 # Generate system info from seed 137 # populates the sinfo map 138 function makesystem(seeds, sinfo, p1, p2, p3, p4, lnf, ecof, sname) { 139 lnf = bw_and(seeds[0], 64) 140 sinfo["x"] = int(seeds[1] / 256) 141 sinfo["y"] = int(seeds[0] / 256) 142 sinfo["govtype"] = int(seeds[1] / 8) % 8 143 sinfo["economy"] = int(seeds[0] / 256) % 8 144 if(sinfo["govtype"] <= 1) 145 sinfo["economy"] = 2 + (sinfo["economy"]%2) + (sinfo["economy"]>3?4:0) 146 ecof = 7 - sinfo["economy"] 147 sinfo["techlev"] = (sinfo["x"] % 4) + ecof + int(sinfo["govtype"] / 2) 148 if((sinfo["govtype"] % 2) == 1) sinfo["techlev"]++ 149 sinfo["population"] = 4 * (sinfo["techlev"]) + sinfo["economy"] + sinfo["govtype"] + 1 150 sinfo["productivity"] = ((ecof + 3) * (sinfo["govtype"] + 4)) * sinfo["population"] * 8 151 sinfo["radius"] = 256 * ((int(seeds[2] / 256) % 16) + 11) + sinfo["x"] 152 # goat soup seed parts 153 sinfo["gsseed_a"] = seeds[1] % 256 154 sinfo["gsseed_b"] = int(seeds[1] / 256) % 256 155 sinfo["gsseed_c"] = seeds[2] % 256 156 sinfo["gsseed_d"] = int(seeds[2] / 256) % 256 157 # name pair indexes 158 p1 = 2 * (int(seeds[2] / 256) % 32); tweakseed(seeds) 159 p2 = 2 * (int(seeds[2] / 256) % 32); tweakseed(seeds) 160 p3 = 2 * (int(seeds[2] / 256) % 32); tweakseed(seeds) 161 p4 = 2 * (int(seeds[2] / 256) % 32); tweakseed(seeds) 162 sname = pairs[p1] pairs[p1+1] pairs[p2] pairs[p2+1] pairs[p3] pairs[p3+1] 163 if(lnf) sname = sname pairs[p4] pairs[p4+1] 164 gsub(/\./, "", sname) # remove all dots from sname 165 sinfo["name"] = sname # write the final name variant 166 # return sinfo 167 } 168 169 # "Goat Soup" planetary description string code 170 171 function gs_rnd(sinfo, a, x) { # accepts system info to modify gsseed 172 x = (sinfo["gsseed_a"] * 2) % 256 173 a = x + sinfo["gsseed_c"] 174 if(sinfo["gsseed_a"] > 127) a++ 175 sinfo["gsseed_a"] = a % 256 176 sinfo["gsseed_c"] = x 177 x = sinfo["gsseed_b"] 178 a = (int(a / 256) + x + sinfo["gsseed_d"]) % 256 179 sinfo["gsseed_b"] = a 180 sinfo["gsseed_d"] = x 181 return a 182 } 183 184 # main desc generator, recursive, modifies sinfo as well 185 function goat_soup(source, sinfo, l, c, i, j, k, v, rnd, dsel) { 186 l = length(source) 187 for(i=0;i<l;i++) { 188 c = ord(substr(source, i+1, 1)) 189 if(c < 128) printf("%c", c) 190 else { 191 if(c <= 164) { 192 rnd = gs_rnd(sinfo) 193 asplit(desc_list[c - 129], dsel, ",") # select the string from list 194 j = ((rnd >= 51) ? 1 : 0) + ((rnd >= 102) ? 1 : 0) 195 j += ((rnd >= 153) ? 1 : 0) + ((rnd >= 204) ? 1 : 0) 196 goat_soup(dsel[j], sinfo) 197 } else { 198 if(c == 176) { # planet name 199 v = sinfo["name"] 200 v = substr(v, 1, 1) tolower(substr(v, 2)) 201 printf("%s", v) 202 } else if(c == 177) { # planet name + ian 203 v = sinfo["name"] 204 v = substr(v, 1, 1) tolower(substr(v, 2)) 205 # find last "e" or "i" occurrence in v 206 j = match(v, /[eia]+$/) 207 if(j == 0) j = length(v) + 1 208 printf("%sian", substr(v, 1, j - 1)) 209 } else if(c == 178) { # random name 210 v = gs_rnd(sinfo) % 4 211 for(j = 0; j <= v; j++) { 212 k = bw_and(62, gs_rnd(sinfo)) 213 printf("%c", (j > 0) ? tolower(pairs0[k]) : pairs0[k]) 214 printf("%c", tolower(pairs0[k+1])) 215 } 216 } else { printf("<bad char in data [%X]>",c); return } 217 } 218 } 219 } 220 } 221 222 # Galaxy builder (populates seeds array and global galaxy arrays) 223 function buildgalaxy(gnum, seeds, si, i) { 224 asplit("23114 584 46931", seeds, " ") 225 for(i=1;i<gnum;i++) galswitch(seeds) 226 split("", galaxy) # global galaxy array 227 split("", plannames) # global galaxy planet names array 228 split("", economies) # economy mapping 229 for(i=0;i<galsize;i++) { 230 split("", si) # init a new system info array 231 makesystem(seeds, si) # populate it 232 galaxy[i] = assocser(si, "|") # serialize into the field 233 plannames[i] = si["name"] # populate the name 234 galcoords_x[i] = si["x"] # populate x coordinate 235 galcoords_y[i] = si["y"] # populate y coordinate 236 economies[i] = si["economy"] # populate economy type 237 } 238 } 239 240 241 # Market functions 242 243 # buy amount a of product i, return amount bought 244 function gamebuy(i, a, t) { 245 if(player["cash"] < 0) t = 0 246 else { 247 t = mymin(localmarket_quantity[i], a) 248 if(goods_units[i] == 0) t = mymin(player["holdspace"], t) 249 t = mymin(t, int(player["cash"] / localmarket_price[i])) 250 } 251 shipshold[i] = int(shipshold[i]) + t 252 localmarket_quantity[i] -= t 253 player["cash"] -= t * localmarket_price[i] 254 player["expense"] += t * localmarket_price[i] 255 if(goods_units[i] == 0) player["holdspace"] -= t 256 return t 257 } 258 259 # sell amount a of product i, return amount sold 260 function gamesell(i, a, t) { 261 t = mymin(shipshold[i], a) 262 shipshold[i] -= t 263 localmarket_quantity[i] += t 264 if(goods_units[i] == 0) player["holdspace"] += t 265 player["cash"] += t * localmarket_price[i] 266 return t 267 } 268 269 # generate market for a particular planetary system 270 # accepts fluctuation byte and economy type number 271 # recreates localmarket_quantity and localmarket_price arrays 272 function genmarket(fluct, econtype, i, q, product, changing) { 273 for(i=0;i<=IDX_ALIEN_ITEMS;i++) { 274 product = econtype * goods_grads[i] 275 changing = bw_and(fluct, goods_masks[i]) 276 q = (goods_bquants[i] + changing - product + 256) % 256 277 if(q > 127) q = 0 278 localmarket_quantity[i] = q % 64 279 q = (goods_bprices[i] + changing + product) % 256 280 localmarket_price[i] = q * 4 281 } 282 if(NO_ALIEN_ITEMS) localmarket_quantity[IDX_ALIEN_ITEMS] = 0 283 } 284 285 # display local market from localmarket_quantity and localmarket_price 286 function displaymarket(i) { 287 for(i=0;i<=IDX_ALIEN_ITEMS;i++) { 288 printf("\n%-16s", goods_names[i]) 289 printf("%-5s", sprintf("%.1f", localmarket_price[i]/10)) 290 printf("\t%u%s", localmarket_quantity[i], unitnames[goods_units[i]]) 291 printf("\t\t%u", shipshold[i]) 292 } 293 } 294 295 # move to system i 296 function gamejump(i, si) { 297 player["currentplanet"] = i 298 player["jumps"]++ 299 assocdes(galaxy[i], si, "|") 300 genmarket(randbyte(), int(si["economy"])) 301 } 302 303 # print data for given system 304 function prisys(sinfo, compressed) { 305 if(compressed) { 306 printf("%10s TL: %2i ", sinfo["name"], sinfo["techlev"] + 1) 307 printf("%-20s %-15s", econnames[sinfo["economy"]], govnames[sinfo["govtype"]]) 308 } else { 309 printf("\nSystem: %s", sinfo["name"]) 310 printf("\nPosition (%i, %i)", sinfo["x"], sinfo["y"]) 311 printf("\nEconomy: (%i) %s", sinfo["economy"], econnames[sinfo["economy"]]) 312 printf("\nGovernment: (%i) %s", sinfo["govtype"], govnames[sinfo["govtype"]]) 313 printf("\nTech level: %2i", sinfo["techlev"] + 1) 314 printf("\nTurnover: %u", sinfo["productivity"]) 315 printf("\nRadius: %u", sinfo["radius"]) 316 printf("\nPopulation: %u billion\n", int(sinfo["population"]/8)) 317 goat_soup("\217 is \227.", sinfo) # generate and print the description 318 if(match(sinfo["name"], /RA..LA/)) # found Raxxla? 319 printf("\n%s", "Wait a sec... Is this the legendary Raxxla?\nWe'll never know for sure...") 320 } 321 } 322 323 # return id of the planet whose name matches passed string 324 # closest to current planet - if none, return current planet 325 function matchsys(s, d, i, p, cd) { 326 p = player["currentplanet"] 327 d = 9999 328 s = toupper(s) # system names are stored in uppercase 329 for(i=0;i<galsize;i++) { 330 if(index(plannames[i], s) == 1) { # found i-th system 331 cd = distance(galcoords_x[i], galcoords_y[i], galcoords_x[p], galcoords_y[p]) 332 if(cd < d) {d = cd; p = i} 333 } 334 } 335 return p 336 } 337 338 # direct command implementations (may be further merged into the REPL directly) 339 340 # rand command implementation 341 function dotweakrand() { game["use_native_rand"] = 1 - game["use_native_rand"] } 342 343 # local command implementation 344 function dolocal(d, i, p, si) { 345 printf("\nGalaxy %i - %s\n", player["galaxynum"], galnames[player["galaxynum"]]) 346 p = int(player["currentplanet"]) 347 for(i=0;i<galsize;i++) { 348 d = distance(galcoords_x[i], galcoords_y[i], galcoords_x[p], galcoords_y[p]) 349 if(d <= game["maxfuel"]) { 350 printf("\n %s ", (d <= player["fuel"]) ? "*" : "-") 351 assocdes(galaxy[i], si, "|") # deserialize current system 352 prisys(si, 1) 353 printf(" (%.1f LY)", d/10) 354 } 355 } 356 } 357 358 # jump to planet name s 359 function dojump(s, dest, d, p, si) { 360 dest = matchsys(s) # find the destination 361 p = int(player["currentplanet"]) 362 if(dest == p) { printf("\nBad jump"); return 0} 363 d = distance(galcoords_x[dest], galcoords_y[dest], galcoords_x[p], galcoords_y[p]) 364 if(d > player["fuel"]) {printf("\nJump too far"); return 0} 365 player["fuel"] -= d 366 gamejump(dest, si) 367 prisys(si, 0) 368 return 1 369 } 370 371 # jump to next galaxy (planet number is preserved) 372 function dogalhyp() { 373 if(player["cash"] > game["galhypcost"]) { 374 player["cash"] -= game["galhypcost"] 375 player["expense"] += game["galhypcost"] 376 player["galaxynum"]++ 377 player["jumps"]++ 378 if(player["galaxynum"] == 9) player["galaxynum"] = 1 379 buildgalaxy(player["galaxynum"], globalseeds) # build a new galaxy 380 } 381 else printf("Not enough credits for hyperspace jump!\nMust have at least %.1f CR", game["galhypcost"]/10) 382 } 383 384 # print planet info 385 function doinfo(s, dest, si) { 386 dest = matchsys(s) # find the system 387 assocdes(galaxy[dest], si, "|") # deserialize found system 388 prisys(si, 0) # print its info 389 } 390 391 # upgrade/up command implementation 392 function doup(a, t, i, ns) { 393 ns = 6 # number of upgrades, including the basic version 394 if(player["upglvl"] == ns - 1) 395 printf("\nYou already are on the maximum upgrade level, enjoy!") 396 else if(a == "") { # no parameter, list available ships 397 printf("\nAvailable upgrades:\n") 398 for(i=player["upglvl"]+1;i<ns;i++) { 399 printf("\n%u. %-13s %-5s %-10s", i, shipnames[i], sprintf("%ut", cargoholds[i]), sprintf("%.1f CR",shipprices[i]/10)) 400 } 401 printf("\n\nType upgrade [number] to upgrade") 402 } else { 403 a = int(a) 404 if(a >= ns || a <= player["upglvl"]) 405 printf("\nInvalid upgrade number!") 406 else if(player["cash"] < shipprices[a]) 407 printf("\nYou need at least %.1f CR to upgrade to %s!", shipprices[a]/10, shipnames[a]) 408 else { # perform the upgrade if cash allows 409 player["upglvl"] = a 410 a = int(cargoholds[a]) 411 t = 0 412 for(i=0;i<=IDX_ALIEN_ITEMS;i++) 413 if(goods_units[i] == 0) t += shipshold[i] 414 if(t > a) {printf("\nHold too full"); return 0} 415 player["holdspace"] = a - t 416 player["cash"] -= shipprices[player["upglvl"]] 417 player["expense"] += shipprices[player["upglvl"]] 418 printf("\nBought %s", shipnames[player["upglvl"]]) 419 printf("\nCargo bay expanded to %dt", cargoholds[player["upglvl"]]) 420 } 421 } 422 } 423 424 # check string s against n options in array a 425 # if matches ith element return i+1 else return 0 426 function stringmatch(s, a, n, i) { 427 s = tolower(s) 428 for(i=0;i<n;i++) 429 if(index(tolower(a[i]), s) == 1) return i+1 430 return 0 431 } 432 433 # sell command implementation (accepts space-separated name and amount) 434 function dosell(s, sp, pname, pquant, i, t) { 435 split(s, sp, " ") 436 pname = sp[1] 437 pquant = int(sp[2]) 438 if(pquant < 1) pquant = 1 439 i = stringmatch(pname, goods_names, IDX_ALIEN_ITEMS + 1) 440 if(i == 0) {printf("\nUnknown product"); return 0} 441 i -= 1 # switch to the real product index 442 t = gamesell(i, pquant) 443 pname = goods_names[i] # update real product name 444 if(t > 0) { 445 printf("\nSelling %i%s of %s", t, unitnames[goods_units[i]], pname) 446 } else printf("\nCannot sell any %s", pname) 447 return 1 448 } 449 450 # buy command implementation (accepts space-separated name and amount) 451 function dobuy(s, sp, pname, pquant, i, t) { 452 split(s, sp, " ") 453 pname = sp[1] 454 pquant = int(sp[2]) 455 if(pquant < 1) pquant = 1 456 i = stringmatch(pname, goods_names, IDX_ALIEN_ITEMS + 1) 457 if(i == 0) {printf("\nUnknown product"); return 0} 458 i -= 1 # switch to the real product index 459 t = gamebuy(i, pquant) 460 pname = goods_names[i] # update real product name 461 if(t > 0) { 462 printf("\nBuying %i%s of %s", t, unitnames[goods_units[i]], pname) 463 } else printf("\nCannot buy any %s", pname) 464 return 1 465 } 466 467 # attempt to buy f tonnes of fuel 468 function gamefuel(f) { 469 if((f + player["fuel"]) > game["maxfuel"]) 470 f = game["maxfuel"] - player["fuel"] 471 if(game["fuelcost"] > 0 && (f * game["fuelcost"] > player["cash"])) 472 f = int(player["cash"] / game["fuelcost"]) 473 player["fuel"] += f 474 player["cash"] -= f * game["fuelcost"] 475 player["expense"] += f * game["fuelcost"] 476 return f 477 } 478 479 # fuel command implementation 480 function dofuel(f) { 481 f = gamefuel(int(10 * f)) 482 if(f == 0) printf("\nCan't buy any fuel") 483 else printf("\nBuying %.1fLY fuel", f/10) 484 return 1 485 } 486 487 # show stock market 488 function domkt() { 489 displaymarket() 490 printf("\n\nFuel: %.1f\nFree cargo space: %it", player["fuel"]/10, player["holdspace"]) 491 } 492 493 # display help 494 function dohelp() { 495 printf("\nCommands are:") 496 printf("\nBuy product amount") 497 printf("\nSell product amount") 498 printf("\nFuel amount (buy amount LY of fuel)") 499 printf("\nJump planetname (limited by fuel)") 500 printf("\nGalhyp (jump to next galaxy)") 501 printf("\nInfo planetname (print info on system)") 502 printf("\nMkt (show market prices)") 503 printf("\nLocal (list systems within 7 lightyears)") 504 printf("\nUpgrade (upgrade your ship)") 505 printf("\nStat (show player statistics)") 506 printf("\nSave playername (save game into current working directory)") 507 printf("\nLoad playername (load game from current working directory)") 508 printf("\nQuit or ^D (exit)") 509 printf("\nHelp (display this text)") 510 printf("\nRand (toggle RNG)") 511 printf("\n\nAbbreviations allowed eg. b fo 5 = Buy Food 5, m = Mkt") 512 } 513 514 # Save/load functionality 515 516 function dosave(savename, fs, fn) { 517 gsub(/[^[:alnum:]]/, "_", savename) # sanitize all non-alnum chars 518 player["cargo"] = assocser(shipshold, "@") 519 fs = assocser(player, "|") 520 delete player["cargo"] 521 fn = savename ".awlite" 522 printf("%s\n", fs) > fn # write the savefile 523 close(fn) 524 printf("\nGame saved in %s", fn) 525 } 526 527 function doload(savename, fn, fs) { 528 gsub(/[^[:alnum:]]/, "_", savename) # sanitize all non-alnum chars 529 fn = savename ".awlite" 530 if((getline fs < fn) > 0) { # read the savefile 531 split("", player) # clear the player array 532 split("", shipshold) # clear the shipshold array 533 assocdes(fs, player, "|") 534 assocdes(player["cargo"], shipshold, "@") 535 delete player["cargo"] 536 split("", globalseeds) # init galaxy seeds 537 buildgalaxy(player["galaxynum"], globalseeds) # build the current galaxy 538 genmarket(0, economies[player["currentplanet"]]) # build local market 539 printf("\nGame loaded from %s", fn) 540 } else printf("\nError reading the savefile!") 541 close(fn) 542 } 543 544 # player statistics and ranking display 545 # ranking formula might be subject to change in future versions 546 function dostat(profind, rank) { 547 profind = 0 # profit margin index 548 rank = 0 549 if(player["expense"] > 0) { 550 profind = (player["cash"]-1000) / player["expense"] 551 if(profind > 1) rank = int(log(profind) / log(2)) + 1 # log base 2 552 if(rank < 0) rank = 0 553 if(rank > 8) rank = 8 554 } 555 printf("\nRank: %s", ranknames[rank]) 556 printf("\n\n========= Money =========") 557 printf("\nBalance %17s", sprintf("%.1f CR",player["cash"]/10)) 558 printf("\nExpenses %16s", sprintf("%.1f CR", player["expense"]/10)) 559 printf("\nProfit margin %11s", sprintf("%.2f%%", profind*100)) 560 printf("\n\n======= Ship info =======") 561 printf("\nName %20s", shipnames[player["upglvl"]]) 562 printf("\nFuel %20s", sprintf("%.1f LY", player["fuel"]/10)) 563 printf("\nCargo space %13s", sprintf("%ut", cargoholds[player["upglvl"]])) 564 printf("\nFree space %14s", sprintf("%ut", player["holdspace"])) 565 printf("\nJumps %19s", sprintf("%u", player["jumps"])) 566 } 567 568 # Game init procedure: first thing to call in the BEGIN block 569 function gameinit() { 570 rng_lastrand = 0 # state for custom PRNG 571 mysrand(12345); # ensure repeatability 572 numForLave = 7 # Lave is the 7th planet in galaxy 1 573 574 split("",game) # overall game state is stored here 575 game["use_native_rand"] = 1 576 game["galhypcost"] = 50000 # 5000 CR 577 game["cargoexpcost"] = 4000 # 400 CR for one-time upgrade 578 game["cargoexpsize"] = 35 # 35t after the upgrade 579 game["fuelcost"] = 2 # 0.2 CR/lightyear 580 game["maxfuel"] = 70 # 7.0 LY tank 581 582 split("",player) # current (saveable) player state is stored here 583 player["currentplanet"] = numForLave # current planet (1 to 256) 584 player["galaxynum"] = 1 # current galaxy (1 to 8) 585 player["cash"] = 1000 # current cash (100 CR) 586 player["expense"] = 0 # for tracking overall expenses 587 player["jumps"] = 0 # for counting interplanetary jumps 588 player["fuel"] = game["maxfuel"] # current fuel amount 589 player["upglvl"] = 0 # player's upgrade level 590 split("",shipshold) # (saveable) contents of cargo bay, up to 16 items 591 592 # constants and tables 593 594 # unit names 595 asplit("t kg g", unitnames, " ") 596 597 # galaxy names (1-indexed) 598 split("Santaari Colesque Lara'tan Angiana Proximus Sol Jaftra Xrata", galnames, " ") 599 600 # government names 601 asplit("Anarchy,Feudal,Multi-gov,Dictatorship,Communist,Confederacy,Democracy,Corporate State", govnames, ",") 602 603 # economy names 604 asplit("Rich Industrial,Average Industrial,Poor Industrial,Mainly Industrial,Mainly Agricultural,Rich Agricultural,Average Agricultural,Poor Agricultural", econnames, ",") 605 606 # rank names 607 asplit("Penniless,Mostly Penniless,Peddler,Dealer,Merchant,Broker,Entrepreneur,Tycoon,Elite", ranknames, ",") 608 609 # ship names 610 asplit("Cobra Mk3,Cobra Mk3 Ext,Python,Boa,Boa 2,Anaconda", shipnames, ",") 611 612 # upgrade prices 613 asplit("0 4000 2000000 4500000 4950000 6500000", shipprices, " ") 614 615 # cargo hold values, t 616 asplit("20 35 100 125 175 750", cargoholds, " ") 617 618 player["holdspace"] = cargoholds[player["upglvl"]] # max cargo hold space 619 620 # Goods 621 622 # Data for DB's price/availability generation system: 623 # Base price, Gradient, Base quantity, Mask, Unit, Name 624 split("", commodities) # will split on demand 625 commodities[0] = "19,-2,6,1,0,Food" 626 commodities[1] = "20,-1,10,3,0,Textiles" 627 commodities[2] = "65,-3,2,7,0,Radioactives" 628 commodities[3] = "40,-5,226,31,0," (CENSORED ? "Robots" : "Slaves") 629 commodities[4] = "83,-5,251,15,0," (CENSORED ? "Beverages" : "Liquors") 630 commodities[5] = "196,8,54,3,0,Luxuries" 631 commodities[6] = "235,29,8,120,0," (CENSORED ? "Rare Species" : "Narcotics") 632 commodities[7] = "154,14,56,3,0,Computers" 633 commodities[8] = "117,6,40,7,0,Machinery" 634 commodities[9] = "78,1,17,31,0,Alloys" 635 commodities[10] = "124,13,29,7,0,Firearms" 636 commodities[11] = "176,-9,220,63,0,Furs" 637 commodities[12] = "32,-1,53,3,0,Minerals" 638 commodities[13] = "97,-1,66,7,1,Gold" 639 commodities[14] = "171,-2,55,31,1,Platinum" 640 commodities[15] = "45,-1,250,15,2,Gem-stones" 641 commodities[16] = "53,15,192,7,0,Alien Items" 642 643 IDX_ALIEN_ITEMS=16 644 645 split("", goods_bprices) # holds base prices 646 split("", goods_grads) # holds gradients 647 split("", goods_bquants) # holds base quantities 648 split("", goods_masks) # holds masks 649 split("", goods_units) # holds measurement units 650 split("", goods_names) # holds goods names 651 for(i in commodities) { # it's pre-ordered anyway 652 split(commodities[i], parts, ",") # we can use 1-based here 653 goods_bprices[i] = int(parts[1]) 654 goods_grads[i] = int(parts[2]) 655 goods_bquants[i] = int(parts[3]) 656 goods_masks[i] = int(parts[4]) 657 goods_units[i] = int(parts[5]) 658 goods_names[i] = parts[6] 659 } 660 661 # localmarket assoc arrays 662 split("", localmarket_quantity) 663 split("", localmarket_price) 664 665 # digrams for planet names 666 asplit("ABOUSEITILETSTONLONUTHNOALLEXEGEZACEBISOUSESARMAINDIREA.ERATENBERALAVETIEDORQUANTEISRION", pairs0, "") 667 asplit("..LEXEGEZACEBISOUSESARMAINDIREA.ERATENBERALAVETIEDORQUANTEISRION", pairs, "") 668 669 # planet description string parts 670 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" 671 asplit(desc_list_str, desc_list, "|") 672 673 galsize = 256 # number of systems in one galaxy 674 675 } 676 677 # main code block 678 BEGIN { 679 gameinit() # init everything 680 split("", globalseeds) # init galaxy seeds 681 buildgalaxy(player["galaxynum"], globalseeds) # build the current galaxy 682 genmarket(0, economies[player["currentplanet"]]) # build local market 683 printf("\nWelcome to awlite 1.8.1\n") 684 dohelp() 685 # start the REPL 686 printf("\n\nCash: %.1f> ", player["cash"]/10) 687 while((getline cmd) > 0) { 688 cmd = tolower(cmd) # accept both uppercase and lowercase 689 spi = index(cmd, " ") # first whitespace in cmd 690 action = (spi == 0) ? cmd : substr(cmd, 1, spi - 1) 691 paramstr = (spi == 0) ? "" : substr(cmd, spi+1) 692 if(cmd == "q" || cmd == "quit") break 693 else if(cmd == "h" || cmd == "help") dohelp() 694 else if(cmd == "r" || cmd == "rand") dotweakrand() 695 else if(cmd == "m" || cmd == "mkt") domkt() 696 else if(cmd == "l" || cmd == "local") dolocal() 697 else if(cmd == "g" || cmd == "galhyp") dogalhyp() 698 else if(cmd == "st" || cmd == "stat") dostat() 699 else if(action == "i" || action == "info") doinfo(paramstr) 700 else if(action == "b" || action == "buy") dobuy(paramstr) 701 else if(action == "s" || action == "sell") dosell(paramstr) 702 else if(action == "j" || action == "jump") dojump(paramstr) 703 else if(action == "f" || action == "fuel") dofuel(paramstr) 704 else if(action == "up" || action == "upgrade") doup(paramstr) 705 else if(action == "save") dosave(paramstr) 706 else if(action == "load") doload(paramstr) 707 else printf("Unknown command") 708 printf("\n\nCash: %.1f> ", player["cash"]/10) 709 } 710 print "\nBye!" 711 }