awlite

POSIX AWK port of Text Elite game
git clone git://git.luxferre.top/awlite.git
Log | Files | Refs | README

commit 2d57dc3c47194e91eda51fd37852ed0ecbd6c4c9
parent 1ab99115386dcd179f1c4c34b54df8446450a5cd
Author: Luxferre <lux@ferre>
Date:   Fri, 26 Jan 2024 15:43:14 +0200

v1.7: stats command, basic ranking

Diffstat:
MREADME | 35+++++++++++++++++++++++++++++------
Mawlite.awk | 48++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 71 insertions(+), 12 deletions(-)

diff --git a/README b/README @@ -42,6 +42,7 @@ From now on, the following commands are available (case-insensitive): * mkt: show local planetary system market prices * local: list planetary systems within 7 lightyears (your max fuel capacity) * hold: expand your cargo bay to 35t for 400 credits (one-time upgrade only) +* stat: show player statistics and overall rank * save (name): save the gamestate in the current working directory * load (name): load the gamestate from the current working directory * help: display an in-game command help screen @@ -56,7 +57,7 @@ Fuel price is fixed at 0.2 CR/LY, you can hold 7LY of fuel at most. == Gameplay differences from the original TE 1.5 C version == -As of the current version, 1.6.3: +As of the current version, 1.7: * multiple typos corrected in text strings * the "cash" and "sneak" commands were removed since v1.6 @@ -75,6 +76,7 @@ As of the current version, 1.6.3: * since v1.6.1, the game gives you a hint if you might have found Raxxla * since v1.6.3, galaxy names are also displayed with "local" command (the names were taken from the Archimedes version of Classic Elite) +* since v1.7, basic ranking and statistics have been introduced To be continued. This list is expected to grow in the future. @@ -115,19 +117,40 @@ set implementation bumps the version number by 0.1, indicating that it's no longer fully command-to-command compatible with the previous one. The first published awlite version was 1.5.8, meaning 8 minor improvements. -- If there are no combat missions or ranks, what are the goals in awlite? +- If there are no combat missions, what are the goals in awlite? Like the original Elite and Text Elite, awlite has no end-game goal. There are, however, some milestones you can achieve even now, for instance: +* reaching the Elite trade rank (in v1.7+ - see below); * reaching a certain amount of credits; * collecting certain amounts of rare valuable items; * visiting all planets in all galaxies (2048 total); * finding Raxxla (v1.6.1+ will give you a hint when you might have done so). -As of now, player ranking system and statistics are in the works and planned -to be introduced in version 1.7 or 1.8. They will be loosely based upon Trade -and Explorer ranking of Elite Dangerous but are going to be unique to awlite. +As of now, player ranking system and statistics are in the works. The basic +system of stats and ranks was introduced in v1.7. It is loosely based upon the +Trade ranks of Elite Dangerous but the formula is fully unique to awlite. + +- How are ranks calculated in awlite v1.7 and above? + +To keep things simple, the formula currently only considers the current cash +balance and overall expenses to calculate the profit margin, then taking log2 +of it. As of now, the following profit margin to rank mapping is in effect: + +* Under 100%: Penniless +* 100% to 200%: Mostly Penniless +* 200% to 400%: Peddler +* 400% to 800%: Dealer +* 800% to 1600%: Merchant +* 1600% to 3200%: Broker +* 3200% to 6400%: Entrepreneur +* 6400% to 12800%: Tycoon +* 12800% and above: Elite + +So, to reach Elite trade rank, you need to make 128 times more money than you +spend. This system might change in future versions, as it's not clear whether +or not this is possible at all. - I found an awesome trade route in awlite. Can I use it in other Elite games? @@ -149,7 +172,7 @@ being designed. - How large is awlite? As of now, the entire game is contained in a single file with a little under -500 SLOC of POSIX AWK code. Future functionality might increase the codebase +550 SLOC of POSIX AWK code. Future functionality might increase the codebase size, but one of the goals is to keep it under 1000 SLOC no matter what. - Why AWK? diff --git a/awlite.awk b/awlite.awk @@ -1,5 +1,5 @@ # awlite: POSIX AWK port of Text Elite -# Version 1.6.3 +# 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 # @@ -20,6 +20,7 @@ # - 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 @@ -249,6 +250,7 @@ function gamebuy(i, a, t) { 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 } @@ -292,6 +294,7 @@ function displaymarket(i) { # move to system i function gamejump(i, si) { player["currentplanet"] = i + player["jumps"]++ assocdes(galaxy[i], si, "|") genmarket(randbyte(), int(si["economy"])) } @@ -368,7 +371,9 @@ function dojump(s, dest, d, p, si) { 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 } @@ -399,6 +404,7 @@ function dohold(a, t, 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 } @@ -454,6 +460,7 @@ function gamefuel(f) { f = int(player["cash"] / game["fuelcost"]) player["fuel"] += f player["cash"] -= f * game["fuelcost"] + player["expense"] += f * game["fuelcost"] return f } @@ -478,11 +485,12 @@ function dohelp() { printf("\nSell product amount") printf("\nFuel amount (buy amount LY of fuel)") printf("\nJump planetname (limited by fuel)") - printf("\nGalhyp (jumps to next galaxy)") - printf("\nInfo planetname (prints info on system)") - printf("\nMkt (shows market prices)") - printf("\nLocal (lists systems within 7 lightyears)") + 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)") @@ -521,6 +529,28 @@ function doload(savename, fn, fs) { 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"] + rank = int(log(1 + profind) / log(2)) # 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 @@ -539,6 +569,8 @@ function gameinit() { 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 @@ -557,6 +589,9 @@ function gameinit() { # 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: @@ -620,7 +655,7 @@ BEGIN { 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.6.3\n") + printf("\nWelcome to awlite 1.7\n") dohelp() # start the REPL printf("\n\nCash: %.1f> ", player["cash"]/10) @@ -635,6 +670,7 @@ BEGIN { 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)