This is my way over engineered version (with implicit_control_flow). (I set up my subroutines with the idea of taking them with me from game to game.)
*label display_number
*params n
*comment param_1: n:(numeric) input number
*if param_count >= 2
*temp p param_2
*else
*temp p false
*comment param_2: p:(boolean|string) inserted before number (assumes $ if true) (optional: defaults to false)
*if param_count >= 3
*temp f param_3
*else
*temp f false
*comment param_3: f:(boolean|string) inserted after number (assumes .00 if true) (optional: defaults to false)
*if param_count >= 4
*temp z param_4
*else
*temp z false
*comment param_4: z:(false|"variable") Return variable: if not false, sets this variable rather than displays number (optional: defaults to false)
*temp x length(n)
*temp d ""
*comment x:place in number where writing from; d:display number
*if round(n) != n
*check_purchase
*if (choice_randomtest) or not(choice_purchase_supported)
*bug n should be a whole number (is currently ${n}). In play through anything after the decimal will be truncated.
*set n round(n-0.5)
*set x length(n)
*if p = false
*set p ""
*if p = true
*set p "$"
*if f = false
*set f ""
*if f = true
*set f ".00"
*if z != false
*if z = true
*bug Invalid parameter: Return variable is ${z}. Acceptable values are "variables" stored as strings or the boolean false.
*set {z} ""
*comment Above line clears z if not false, and will throw a non-existent variable error if z is not a "variable".
*label display_number_loop
*set d (n#x)&d
*set x - 1
*if x = 0
*label display_number_exit
*if z = false
${p}${d}
*else
*set {z} p&d
*return
*if (n#x) = "."
*bug
*if ((length(n)-x) modulo 3) = 0
*set d ","&d
*goto display_number_loop
There’s one parameter (the number) which is not optional, then another 3 which are optional, and if it’s not a whole number, it runs into a bug (unless the game is set up for purchase), which is that the whole *check_purchase thing is.
Bear in mind this may confuse foreign readers, who might use commas to mark decimals and periods to separate groups of three. So they’d expect 999999999 as 999.999.999,00. Or in other countries they might expect 999 999 999,00.
I ended up using a simple, brute force method to (where applicable) turn any value up to $999999 into something more appropriate for display, e.g. $23,795, using the ability to extract / overwrite particular letters or numbers in variable values. In short, it treats the value as a string, not numeric, since it’s purely for display purposes.
I’ll lay out the whole thing here in step-by-step fashion but it should be easy enough to tweak to suit particular needs, and thereby reduce the number of lines used / needed.
*set word "${wealth}"
*comment turn value into a 6-digit number by prefixing with zeros
*if length(word) = 1
*set word (("0"&"0")&("0"&"0"))&("0"&(word#1))
*if length(word) = 2
*set word (("0"&"0")&("0"&"0"))&((word#1)&(word#2))
*if length(word) = 3
*set word (("0"&"0")&("0"&(word#1)))&((word#2)&(word#3))
*if length(word) = 4
*set word (("0"&"0")&((word#1)&(word#2)))&((word#3)&(word#4))
*if length(word) = 5
*set word (("0"&(word#1))&((word#2)&(word#3)))&((word#4)&(word#5))
*comment insert comma in middle of 6-digit currency value
*if length(word) = 6
*set word (((word#1)&(word#2))&((word#3)&(",")))&(((word#4)&(word#5))&(word#6))
*comment remove leading zeros one at a time, including comma if not needed
*if (word#1) = "0"
*set word (((word#2)&(word#3))&((word#4)&(word#5)))&((word#6)&(word#7))
*if (word#1) = "0"
*set word (((word#2)&(word#3))&((word#4)&(word#5)))&(word#6)
*if (word#1) = "0"
*set word ((word#3)&(word#4))&(word#5)
*if (word#1) = "0"
*set word (word#2)&(word#3)
*if (word#1) = "0"
*set word (word#2)
Note that while the following, more obvious method works in practice, it actually generates a ‘fake bug’ in QuickTest on the *set lines (in the event the value of word is fewer than x-characters in length, despite the specific *if condition).
*set word "${wealth}"
*if length(word) < 4
*goto next
*if length(word) = 4
*set word (((word#1)&(","))&((word#2)&(word#3)))&(word#4)
*goto next
*if length(word) = 5
*set word (((word#1)&(word#2))&((",")&(word#3)))&((word#4)&(word#5))
*goto next
*if length(word) = 6
*set word (((word#1)&(word#2))&((word#3)&(",")))&(((word#4)&(word#5))&(word#6))
*goto next
*label next