removed support for structs. It was too much hassle and complexity and subtle bugs.

This commit is contained in:
Irmen de Jong 2021-04-29 00:01:20 +02:00
parent 1bde7c7718
commit a9a7068818
45 changed files with 128 additions and 10648 deletions

View File

@ -36,7 +36,6 @@ What does Prog8 provide?
- conditional branches
- floating point operations (requires the C64 Basic ROM routines for this)
- 'when' statement to provide a concise jump table alternative to if/elseif chains
- structs to group together sets of variables and manipulate them at once
- many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``sort`` and ``reverse``
- various powerful built-in libraries to do I/O, number conversions, graphics and more
- convenience abstractions for low level aspects such as ZeroPage handling, program startup, explicit memory addresses

View File

@ -1,7 +1,6 @@
package prog8.compiler
import prog8.ast.IFunctionCall
import prog8.ast.INameScope
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.*
@ -84,6 +83,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
val sub = scope.definingSubroutine()
if (sub != null) {
// move vardecls of the scope into the upper scope. Make sure the position remains the same!
// TODO THIS HAS ALREADY BEEN TAKEN CARE OF AT THE START????
val replacements = mutableListOf<IAstModification>()
val movements = mutableListOf<IAstModification.InsertFirst>()

View File

@ -317,7 +317,7 @@ private fun writeAssembly(programAst: Program,
programAst.processAstBeforeAsmGeneration(errors, compilerOptions.compTarget)
errors.report()
// printAst(programAst)
printAst(programAst)
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
val assembly = asmGeneratorFor(compilerOptions.compTarget,

View File

@ -418,30 +418,6 @@ internal class AstChecker(private val program: Program,
}
}
val targetIdent = assignment.target.identifier
if(targetIdent!=null) {
val targetVar = targetIdent.targetVarDecl(program)
if(targetVar?.struct != null) {
val sourceStructLv = assignment.value as? ArrayLiteralValue
if (sourceStructLv != null) {
if (sourceStructLv.value.size != targetVar.struct?.numberOfElements)
errors.err("number of elements doesn't match struct definition", sourceStructLv.position)
} else {
val sourceIdent = assignment.value as? IdentifierReference
if (sourceIdent != null) {
val sourceVar = sourceIdent.targetVarDecl(program)
if (sourceVar?.struct != null) {
if (sourceVar.struct !== targetVar.struct)
errors.err("assignment of different struct types", assignment.position)
} else if(sourceVar?.isArray==true) {
if((sourceVar.value as ArrayLiteralValue).value.size != targetVar.struct?.numberOfElements)
errors.err("number of elements doesn't match struct definition", sourceVar.position)
}
}
}
}
}
val targetDt = assignment.target.inferType(program)
val valueDt = assignment.value.inferType(program)
if(valueDt.isKnown && !(valueDt isAssignableTo targetDt)) {
@ -561,17 +537,6 @@ internal class AstChecker(private val program: Program,
when(decl.type) {
VarDeclType.VAR, VarDeclType.CONST -> {
if(decl.datatype==DataType.STRUCT) {
if(decl.struct==null)
throw FatalAstException("struct vardecl should be linked to its struct $decl")
if(decl.zeropage==ZeropageWish.PREFER_ZEROPAGE || decl.zeropage==ZeropageWish.REQUIRE_ZEROPAGE)
err("struct can not be in zeropage")
}
if(decl.struct!=null) {
if(decl.zeropage==ZeropageWish.PREFER_ZEROPAGE || decl.zeropage==ZeropageWish.REQUIRE_ZEROPAGE)
err("struct can not be in zeropage")
}
when(decl.value) {
null -> {
// a vardecl without an initial value, don't bother with it
@ -581,30 +546,8 @@ internal class AstChecker(private val program: Program,
checkValueTypeAndRangeString(decl.datatype, decl.value as StringLiteralValue)
}
is ArrayLiteralValue -> {
if(decl.datatype==DataType.STRUCT) {
val struct = decl.struct!!
val structLv = decl.value as ArrayLiteralValue
if(struct.numberOfElements != structLv.value.size) {
errors.err("struct value has incorrect number of elements", structLv.position)
return
}
for(value in structLv.value.zip(struct.statements)) {
val memberdecl = value.second as VarDecl
val constValue = value.first.constValue(program)
if(constValue==null) {
errors.err("struct literal value for field '${memberdecl.name}' should consist of compile-time constants", value.first.position)
return
}
val memberDt = memberdecl.datatype
if(!checkValueTypeAndRange(memberDt, constValue)) {
errors.err("type of struct member value is not compatible with member field '${memberdecl.name}'", value.first.position)
return
}
}
} else {
val arraySpec = decl.arraysize ?: ArrayIndex.forArray(decl.value as ArrayLiteralValue)
checkValueTypeAndRangeArray(decl.datatype, decl.struct, arraySpec, decl.value as ArrayLiteralValue)
}
val arraySpec = decl.arraysize ?: ArrayIndex.forArray(decl.value as ArrayLiteralValue)
checkValueTypeAndRangeArray(decl.datatype, arraySpec, decl.value as ArrayLiteralValue)
}
is NumericLiteralValue -> {
checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue)
@ -648,14 +591,7 @@ internal class AstChecker(private val program: Program,
val declValue = decl.value
if(declValue!=null && decl.type==VarDeclType.VAR) {
if(decl.datatype==DataType.STRUCT) {
val valueIdt = declValue.inferType(program)
if(!valueIdt.isKnown)
throw AstException("unknown dt")
val valueDt = valueIdt.typeOrElse(DataType.STRUCT)
if(valueDt !in ArrayDatatypes)
err("initialisation of struct should be with array value", declValue.position)
} else if (!declValue.inferType(program).istype(decl.datatype)) {
if (!declValue.inferType(program).istype(decl.datatype)) {
err("initialisation value has incompatible type (${declValue.inferType(program)}) for the variable (${decl.datatype})", declValue.position)
}
}
@ -803,7 +739,7 @@ internal class AstChecker(private val program: Program,
errors.err("floating point used, but that is not enabled via options", array.position)
}
val arrayspec = ArrayIndex.forArray(array)
checkValueTypeAndRangeArray(array.type.typeOrElse(DataType.STRUCT), null, arrayspec, array)
checkValueTypeAndRangeArray(array.type.typeOrElse(DataType.STRUCT), arrayspec, array)
}
fun isPassByReferenceElement(e: Expression): Boolean {
@ -1209,24 +1145,6 @@ internal class AstChecker(private val program: Program,
super.visit(whenChoice)
}
override fun visit(structDecl: StructDecl) {
// a struct can only contain 1 or more vardecls and can not be nested
if(structDecl.statements.isEmpty())
errors.err("struct must contain at least one member", structDecl.position)
for(member in structDecl.statements){
val decl = member as? VarDecl
if(decl==null)
errors.err("struct can only contain variable declarations", structDecl.position)
else {
if(decl.zeropage==ZeropageWish.REQUIRE_ZEROPAGE || decl.zeropage==ZeropageWish.PREFER_ZEROPAGE)
errors.err("struct can not contain zeropage members", decl.position)
if(decl.datatype !in NumericDatatypes)
errors.err("structs can only contain numerical types", decl.position)
}
}
}
private fun checkFunctionOrLabelExists(target: IdentifierReference, statement: Statement): Statement? {
val targetStatement = target.targetStatement(program)
if(targetStatement is Label || targetStatement is Subroutine || targetStatement is BuiltinFunctionStatementPlaceholder)
@ -1250,8 +1168,7 @@ internal class AstChecker(private val program: Program,
else false
}
private fun checkValueTypeAndRangeArray(targetDt: DataType, struct: StructDecl?,
arrayspec: ArrayIndex, value: ArrayLiteralValue) : Boolean {
private fun checkValueTypeAndRangeArray(targetDt: DataType, arrayspec: ArrayIndex, value: ArrayLiteralValue) : Boolean {
fun err(msg: String) : Boolean {
errors.err(msg, value.position)
return false
@ -1324,22 +1241,6 @@ internal class AstChecker(private val program: Program,
}
return err("invalid float array initialization value ${value.type}, expected $targetDt")
}
DataType.STRUCT -> {
if(value.type.typeOrElse(DataType.STRUCT) in ArrayDatatypes) {
if(value.value.size != struct!!.numberOfElements)
return err("number of values is not the same as the number of members in the struct")
for(elt in value.value.zip(struct.statements)) {
val vardecl = elt.second as VarDecl
val valuetype = elt.first.inferType(program)
if (!valuetype.isKnown || valuetype isNotAssignableTo vardecl.datatype) {
errors.err("invalid struct member init value type $valuetype, expected ${vardecl.datatype}", elt.first.position)
return false
}
}
return true
}
return false
}
else -> return false
}
}
@ -1442,15 +1343,6 @@ internal class AstChecker(private val program: Program,
DataType.UWORD -> sourceDatatype== DataType.UBYTE || sourceDatatype== DataType.UWORD
DataType.FLOAT -> sourceDatatype in NumericDatatypes
DataType.STR -> sourceDatatype== DataType.STR
DataType.STRUCT -> {
if(sourceDatatype==DataType.STRUCT) {
val structLv = sourceValue as ArrayLiteralValue
val numValues = structLv.value.size
val targetstruct = target.identifier!!.targetVarDecl(program)!!.struct!!
return targetstruct.numberOfElements == numValues
}
false
}
else -> {
errors.err("cannot assign new value to variable of type $targetDatatype", position)
false

View File

@ -2,11 +2,7 @@ package prog8.compiler.astprocessing
import prog8.ast.Module
import prog8.ast.Program
import prog8.ast.base.DataType
import prog8.ast.base.NumericDatatypes
import prog8.ast.base.Position
import prog8.ast.expressions.ArrayLiteralValue
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.expressions.StringLiteralValue
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
@ -66,29 +62,6 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
if(decl.name in compTarget.machine.opcodeNames)
errors.err("can't use a cpu opcode name as a symbol: '${decl.name}'", decl.position)
if(decl.datatype==DataType.STRUCT) {
if (decl.structHasBeenFlattened)
return super.visit(decl) // don't do this multiple times
if (decl.struct == null) {
errors.err("undefined struct type", decl.position)
return super.visit(decl)
}
if (decl.struct!!.statements.any { (it as VarDecl).datatype !in NumericDatatypes })
return super.visit(decl) // a non-numeric member, not supported. proper error is given by AstChecker later
if (decl.value is NumericLiteralValue) {
errors.err("you cannot initialize a struct using a single value", decl.position)
return super.visit(decl)
}
if (decl.value != null && decl.value !is ArrayLiteralValue) {
errors.err("initializing a struct requires array literal value", decl.value?.position ?: decl.position)
return super.visit(decl)
}
}
val existing = program.namespace.lookup(listOf(decl.name), decl)
if (existing != null && existing !== decl)
nameError(decl.name, decl.position, existing)
@ -169,14 +142,4 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
super.visit(string)
}
override fun visit(structDecl: StructDecl) {
for(member in structDecl.statements){
val decl = member as? VarDecl
if(decl!=null && decl.datatype !in NumericDatatypes)
errors.err("structs can only contain numerical types", decl.position)
}
super.visit(structDecl)
}
}

View File

@ -2,10 +2,8 @@ package prog8.compiler.astprocessing
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.DataType
import prog8.ast.expressions.BinaryExpression
import prog8.ast.expressions.StringLiteralValue
import prog8.ast.statements.AnonymousScope
import prog8.ast.statements.ParameterVarDecl
import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl
@ -15,19 +13,6 @@ import prog8.ast.walk.IAstModification
internal class AstVariousTransforms(private val program: Program) : AstWalker() {
override fun before(decl: VarDecl, parent: Node): Iterable<IAstModification> {
// is it a struct variable? then define all its struct members as mangled names,
// and include the original decl as well.
if(decl.datatype==DataType.STRUCT && !decl.structHasBeenFlattened) {
val decls = decl.flattenStructMembers()
decls.add(decl)
val result = AnonymousScope(decls, decl.position)
return listOf(IAstModification.ReplaceNode(decl, result, parent))
}
return noModifications
}
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
// For non-kernal subroutines and non-asm parameters:
// inject subroutine params as local variables (if they're not there yet).

View File

@ -1,7 +1,12 @@
package prog8.compiler.astprocessing
import prog8.ast.*
import prog8.ast.base.*
import prog8.ast.IFunctionCall
import prog8.ast.Module
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.ArrayDatatypes
import prog8.ast.base.DataType
import prog8.ast.base.FatalAstException
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
@ -18,7 +23,6 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
// - in every block and module, most directives and vardecls are moved to the top. (not in subroutines!)
// - the 'start' subroutine is moved to the top.
// - (syntax desugaring) a vardecl with a non-const initializer value is split into a regular vardecl and an assignment statement.
// - (syntax desugaring) struct value assignment is expanded into several struct member assignments.
// - in-place assignments are reordered a bit so that they are mostly of the form A = A <operator> <rest>
// - sorts the choices in when statement.
// - insert AddressOf (&) expression where required (string params to a UWORD function param etc).
@ -200,40 +204,10 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
return noModifications
}
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
val declValue = decl.value
if(declValue!=null && decl.type== VarDeclType.VAR && decl.datatype in NumericDatatypes) {
val declConstValue = declValue.constValue(program)
if(declConstValue==null) {
val subroutine = decl.definingSubroutine() as? INameScope
if(subroutine!=null) {
// move the vardecl (without value) to the scope of the defining subroutine and put a regular assignment in its place here.
decl.value = null
decl.allowInitializeWithZero = false
val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, decl.position)
val assign = Assignment(target, declValue, decl.position)
return listOf(
IAstModification.ReplaceNode(decl, assign, parent),
IAstModification.InsertFirst(decl, subroutine)
)
}
}
}
return noModifications
}
override fun before(assignment: Assignment, parent: Node): Iterable<IAstModification> {
val valueType = assignment.value.inferType(program)
val targetType = assignment.target.inferType(program)
if(targetType.istype(DataType.STRUCT) && (valueType.istype(DataType.STRUCT) || valueType.typeOrElse(DataType.STRUCT) in ArrayDatatypes )) {
if (assignment.value is ArrayLiteralValue) {
errors.err("cannot assign array literal here, use separate assignment per field", assignment.position)
} else {
return copyStructValue(assignment)
}
}
if(targetType.typeOrElse(DataType.STRUCT) in ArrayDatatypes && valueType.typeOrElse(DataType.STRUCT) in ArrayDatatypes ) {
if (assignment.value is ArrayLiteralValue) {
errors.err("cannot assign array literal here, use separate assignment per element", assignment.position)
@ -330,73 +304,4 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
)
return listOf(IAstModification.ReplaceNode(assign, memcopy, assign.parent))
}
private fun copyStructValue(structAssignment: Assignment): List<IAstModification> {
val identifier = structAssignment.target.identifier!!
val targetVar = identifier.targetVarDecl(program)!!
val struct = targetVar.struct!!
when (structAssignment.value) {
is IdentifierReference -> {
val sourceVar = (structAssignment.value as IdentifierReference).targetVarDecl(program)!!
val memsize = struct.memsize(program.memsizer)
when {
sourceVar.struct!=null -> {
// struct memberwise copy
val sourceStruct = sourceVar.struct!!
if(sourceStruct!==targetVar.struct) {
errors.err("struct type mismatch", structAssignment.position)
return listOf()
}
if(struct.statements.size!=sourceStruct.statements.size) {
errors.err("struct element count mismatch", structAssignment.position)
return listOf()
}
if(memsize!=sourceStruct.memsize(program.memsizer)) {
errors.err("memory size mismatch", structAssignment.position)
return listOf()
}
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), structAssignment.position),
mutableListOf(
AddressOf(structAssignment.value as IdentifierReference, structAssignment.position),
AddressOf(identifier, structAssignment.position),
NumericLiteralValue.optimalInteger(memsize, structAssignment.position)
),
true,
structAssignment.position
)
return listOf(IAstModification.ReplaceNode(structAssignment, memcopy, structAssignment.parent))
}
sourceVar.isArray -> {
val array = sourceVar.value as ArrayLiteralValue
if(struct.statements.size!=array.value.size) {
errors.err("struct element count mismatch", structAssignment.position)
return listOf()
}
if(memsize!=array.memsize(program.memsizer)) {
errors.err("memory size mismatch", structAssignment.position)
return listOf()
}
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), structAssignment.position),
mutableListOf(
AddressOf(structAssignment.value as IdentifierReference, structAssignment.position),
AddressOf(identifier, structAssignment.position),
NumericLiteralValue.optimalInteger(memsize, structAssignment.position)
),
true,
structAssignment.position
)
return listOf(IAstModification.ReplaceNode(structAssignment, memcopy, structAssignment.parent))
}
else -> {
throw FatalAstException("can only assign arrays or structs to structs")
}
}
}
is ArrayLiteralValue -> {
throw IllegalArgumentException("not going to do a structLv assignment here")
}
else -> throw FatalAstException("strange struct value")
}
}
}

View File

@ -20,7 +20,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
val declValue = decl.value
if(decl.type==VarDeclType.VAR && declValue!=null && decl.struct==null) {
if(decl.type==VarDeclType.VAR && declValue!=null) {
val valueDt = declValue.inferType(program)
if(!valueDt.istype(decl.datatype)) {

View File

@ -4,7 +4,6 @@ import prog8.ast.IMemSizer
import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.StructDecl
import prog8.ast.statements.VarDecl
import prog8.compiler.CompilerException
import kotlin.math.*
@ -105,7 +104,6 @@ private val functionSignatures: List<FSignature> = listOf(
FSignature("abs" , true, listOf(FParam("value", NumericDatatypes)), null, ::builtinAbs), // type depends on argument
FSignature("len" , true, listOf(FParam("values", IterableDatatypes)), null, ::builtinLen), // type is UBYTE or UWORD depending on actual length
FSignature("sizeof" , true, listOf(FParam("object", DataType.values().toSet())), DataType.UBYTE, ::builtinSizeof),
FSignature("offsetof" , true, listOf(FParam("object", DataType.values().toSet())), DataType.UBYTE, ::builtinOffsetof),
// normal functions follow:
FSignature("sgn" , true, listOf(FParam("value", NumericDatatypes)), DataType.BYTE, ::builtinSgn ),
FSignature("sin" , true, listOf(FParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::sin) },
@ -289,28 +287,6 @@ private fun builtinAbs(args: List<Expression>, position: Position, program: Prog
}
}
private fun builtinOffsetof(args: List<Expression>, position: Position, program: Program, memsizer: IMemSizer): NumericLiteralValue {
// 1 arg, type = anything, result type = ubyte
if(args.size!=1)
throw SyntaxError("offsetof requires one argument", position)
val idref = args[0] as? IdentifierReference
?: throw SyntaxError("offsetof argument should be an identifier", position)
val vardecl = idref.targetVarDecl(program)!!
val struct = vardecl.struct
if (struct == null || vardecl.datatype == DataType.STRUCT)
throw SyntaxError("offsetof can only be used on struct members", position)
val membername = idref.nameInSource.last()
var offset = 0
for(member in struct.statements) {
if((member as VarDecl).name == membername)
return NumericLiteralValue(DataType.UBYTE, offset, position)
offset += memsizer.memorySize(member.datatype)
}
throw SyntaxError("undefined struct member", position)
}
private fun builtinSizeof(args: List<Expression>, position: Position, program: Program, memsizer: IMemSizer): NumericLiteralValue {
// 1 arg, type = anything, result type = ubyte
if(args.size!=1)
@ -323,21 +299,12 @@ private fun builtinSizeof(args: List<Expression>, position: Position, program: P
val target = (args[0] as IdentifierReference).targetStatement(program)
?: throw CannotEvaluateException("sizeof", "no target")
fun structSize(target: StructDecl) = NumericLiteralValue(DataType.UBYTE, target.memsize(memsizer), position)
return when {
dt.typeOrElse(DataType.STRUCT) in ArrayDatatypes -> {
val length = (target as VarDecl).arraysize!!.constIndex() ?: throw CannotEvaluateException("sizeof", "unknown array size")
val elementDt = ArrayElementTypes.getValue(dt.typeOrElse(DataType.STRUCT))
numericLiteral(memsizer.memorySize(elementDt) * length, position)
}
dt.istype(DataType.STRUCT) -> {
when (target) {
is VarDecl -> structSize(target.struct!!)
is StructDecl -> structSize(target)
else -> throw CompilerException("weird struct type $target")
}
}
dt.istype(DataType.STR) -> throw SyntaxError("sizeof str is undefined, did you mean len?", position)
else -> NumericLiteralValue(DataType.UBYTE, memsizer.memorySize(dt.typeOrElse(DataType.STRUCT)), position)
}
@ -374,7 +341,6 @@ private fun builtinLen(args: List<Expression>, position: Position, program: Prog
val refLv = target.value as? StringLiteralValue ?: throw CannotEvaluateException("len", "stringsize unknown")
NumericLiteralValue.optimalInteger(refLv.value.length, args[0].position)
}
DataType.STRUCT -> throw SyntaxError("cannot use len on struct, did you mean sizeof?", args[0].position)
in NumericDatatypes -> throw SyntaxError("cannot use len on numeric value, did you mean sizeof?", args[0].position)
else -> throw CompilerException("weird datatype")
}

View File

@ -379,14 +379,8 @@ internal class AsmGen(private val program: Program,
out("\n; non-zeropage variables")
val vars = statements.filterIsInstance<VarDecl>().filter { it.type==VarDeclType.VAR }
// first output the flattened struct member variables *in order*
// after that, the other variables sorted by their datatype
val (structMembers, normalVars) = vars.partition { it.struct!=null }
structMembers.forEach { vardecl2asm(it) }
// special treatment for string types: merge strings that are identical
val encodedstringVars = normalVars
val encodedstringVars = vars
.filter {it.datatype == DataType.STR }
.map {
val str = it.value as StringLiteralValue
@ -400,7 +394,7 @@ internal class AsmGen(private val program: Program,
}
// non-string variables
normalVars.filter{ it.datatype != DataType.STR }.sortedBy { it.datatype }.forEach {
vars.filter{ it.datatype != DataType.STR }.sortedBy { it.datatype }.forEach {
if(it.makeScopedName(it.name) !in allocatedZeropageVariables)
vardecl2asm(it)
}
@ -437,10 +431,10 @@ internal class AsmGen(private val program: Program,
"$" + it.number.toInt().toString(16).padStart(4, '0')
}
is AddressOf -> {
it.identifier.firstStructVarName(program) ?: asmSymbolName(it.identifier)
asmSymbolName(it.identifier)
}
is IdentifierReference -> {
it.firstStructVarName(program) ?: asmSymbolName(it)
asmSymbolName(it)
}
else -> throw AssemblyError("weird array elt dt")
}
@ -501,14 +495,8 @@ internal class AsmGen(private val program: Program,
return newName
}
internal fun asmSymbolName(identifier: IdentifierReference): String {
return if(identifier.memberOfStruct(program)!=null) {
val name = identifier.targetVarDecl(program)!!.name
fixNameSymbols(name)
} else {
fixNameSymbols(identifier.nameInSource.joinToString("."))
}
}
internal fun asmSymbolName(identifier: IdentifierReference) =
fixNameSymbols(identifier.nameInSource.joinToString("."))
internal fun asmSymbolName(regs: RegisterOrPair): String =
if(regs in Cx16VirtualRegisters)
@ -516,14 +504,8 @@ internal class AsmGen(private val program: Program,
else
throw AssemblyError("no symbol name for register $regs")
internal fun asmVariableName(identifier: IdentifierReference): String {
return if(identifier.memberOfStruct(program)!=null) {
val name = identifier.targetVarDecl(program)!!.name
fixNameSymbols(name)
} else {
fixNameSymbols(identifier.nameInSource.joinToString("."))
}
}
internal fun asmVariableName(identifier: IdentifierReference) =
fixNameSymbols(identifier.nameInSource.joinToString("."))
internal fun asmSymbolName(name: String) = fixNameSymbols(name)
internal fun asmVariableName(name: String) = fixNameSymbols(name)
@ -671,7 +653,7 @@ internal class AsmGen(private val program: Program,
when(stmt) {
is ParameterVarDecl -> { /* subroutine parameter vardecls don't get any special treatment here */ }
is VarDecl -> translate(stmt)
is StructDecl, is NopStatement -> {}
is NopStatement -> {}
is Directive -> translate(stmt)
is Return -> translate(stmt)
is Subroutine -> translateSubroutine(stmt)

View File

@ -145,7 +145,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
SourceStorageKind.EXPRESSION -> {
when(val value = assign.source.expression!!) {
is AddressOf -> {
val sourceName = value.identifier.firstStructVarName(program) ?: asmgen.asmVariableName(value.identifier)
val sourceName = asmgen.asmVariableName(value.identifier)
assignAddressOf(assign.target, sourceName)
}
is NumericLiteralValue -> throw AssemblyError("source kind should have been literalnumber")

View File

@ -3,7 +3,8 @@ package prog8.optimizer
import prog8.ast.INameScope
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.expressions.*
import prog8.ast.expressions.BinaryExpression
import prog8.ast.expressions.augmentAssignmentOperators
import prog8.ast.statements.AssignTarget
import prog8.ast.statements.Assignment
import prog8.ast.walk.AstWalker

View File

@ -175,7 +175,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
}
fun unused(decl: VarDecl): Boolean {
if(decl.type!=VarDeclType.VAR || decl.datatype==DataType.STRUCT || decl.autogeneratedDontRemove || decl.parent is StructDecl)
if(decl.type!=VarDeclType.VAR || decl.datatype==DataType.STRUCT || decl.autogeneratedDontRemove)
return false
if(decl.definingBlock() !in usedBlocks)

View File

@ -1,13 +1,11 @@
package prog8.optimizer
import prog8.ast.INameScope
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.ArrayIndex
import prog8.ast.statements.AssignTarget
import prog8.ast.statements.ForLoop
import prog8.ast.statements.VarDecl
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compiler.IErrorReporter
@ -30,6 +28,28 @@ internal class VarConstantValueTypeAdjuster(private val program: Program, privat
errors.err(x.message, x.position)
}
// move a vardecl to the scope of the defining subroutine and put a regular assignment in its place here (if it has a value)
if(decl.type== VarDeclType.VAR && decl.datatype in NumericDatatypes) {
val subroutine = decl.definingSubroutine() as? INameScope
if(subroutine!=null) {
val declValue = decl.value
decl.value = null
decl.allowInitializeWithZero = false
return if(declValue==null) {
listOf(
IAstModification.Remove(decl, parent as INameScope),
IAstModification.InsertFirst(decl, subroutine)
)
} else {
val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, decl.position)
val assign = Assignment(target, declValue, decl.position)
listOf(
IAstModification.ReplaceNode(decl, assign, parent),
IAstModification.InsertFirst(decl, subroutine)
)
}
}
}
return noModifications
}
}
@ -189,7 +209,6 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
}
else -> {
// nothing to do for this type
// this includes strings and structs
}
}
}

View File

@ -27,7 +27,7 @@ internal class StatementOptimizer(private val program: Program,
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
for(returnvar in subsThatNeedReturnVariable) {
val decl = VarDecl(VarDeclType.VAR, returnvar.second, ZeropageWish.DONTCARE, null, retvarName, null, null, false, true, returnvar.third)
val decl = VarDecl(VarDeclType.VAR, returnvar.second, ZeropageWish.DONTCARE, null, retvarName, null, false, true, returnvar.third)
returnvar.first.statements.add(0, decl)
}
subsThatNeedReturnVariable.clear()

View File

@ -52,7 +52,7 @@ internal class UnusedCodeRemover(private val program: Program,
private fun reportUnreachable(stmt: Statement, parent: INameScope) {
when(val next = parent.nextSibling(stmt)) {
null, is Label, is Directive, is VarDecl, is InlineAssembly, is Subroutine, is StructDecl -> {}
null, is Label, is Directive, is VarDecl, is InlineAssembly, is Subroutine -> {}
else -> errors.warn("unreachable code", next.position)
}
}

View File

@ -21,7 +21,6 @@ import prog8.compiler.target.c64.C64MachineDefinition.FLOAT_MAX_POSITIVE
import prog8.compiler.target.c64.C64MachineDefinition.Mflpt5
import prog8.compiler.target.cbm.Petscii
import prog8.compiler.target.cx16.CX16MachineDefinition.CX16Zeropage
import java.io.CharConversionException
import java.nio.file.Path
import kotlin.test.*
@ -503,7 +502,7 @@ class TestMemory {
@Test
private fun createTestProgramForMemoryRefViaVar(address: Int, vartype: VarDeclType): AssignTarget {
val decl = VarDecl(vartype, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", null, NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
val decl = VarDecl(vartype, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
val memexpr = IdentifierReference(listOf("address"), Position.DUMMY)
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
@ -523,7 +522,7 @@ class TestMemory {
@Test
fun testInValidRamC64_variable() {
val decl = VarDecl(VarDeclType.VAR, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", null, null, false, false, Position.DUMMY)
val decl = VarDecl(VarDeclType.VAR, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", null, false, false, Position.DUMMY)
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
@ -536,7 +535,7 @@ class TestMemory {
@Test
fun testInValidRamC64_memmap_variable() {
val address = 0x1000
val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", null, NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
@ -549,7 +548,7 @@ class TestMemory {
@Test
fun testNotInValidRamC64_memmap_variable() {
val address = 0xd020
val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", null, NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
@ -561,7 +560,7 @@ class TestMemory {
@Test
fun testInValidRamC64_array() {
val decl = VarDecl(VarDeclType.VAR, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", null, null, false, false, Position.DUMMY)
val decl = VarDecl(VarDeclType.VAR, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", null, false, false, Position.DUMMY)
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
@ -575,7 +574,7 @@ class TestMemory {
@Test
fun testInValidRamC64_array_memmapped() {
val address = 0x1000
val decl = VarDecl(VarDeclType.MEMORY, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", null, NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
val decl = VarDecl(VarDeclType.MEMORY, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
@ -589,7 +588,7 @@ class TestMemory {
@Test
fun testNotValidRamC64_array_memmapped() {
val address = 0xe000
val decl = VarDecl(VarDeclType.MEMORY, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", null, NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
val decl = VarDecl(VarDeclType.MEMORY, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)

View File

@ -1,993 +0,0 @@
%import textio
%import conv
%import diskio
%import string
%import test_stack
%option no_sysinit
%zeropage basicsafe
; Prog8 adaptation of the Text-Elite galaxy10 system trading simulation engine.
; Original C-version obtained from: http://www.elitehomepage.org/text/index.htm
; Note: this program is compatible with C64 and CX16.
perf10 {
const ubyte numforLave = 7 ; Lave is 7th generated planet10 in galaxy10 one
const ubyte numforZaonce = 129
const ubyte numforDiso = 147
const ubyte numforRiedquat = 46
sub start() {
txt.lowercase()
txt.print("\u000c\n --- TextElite v1.1 ---\n")
galaxy10.travel_to(1, numforLave)
market10.init(0) ; Lave's market10 is seeded with 0
ship10.init()
planet10.display(false)
repeat {
; test_stack.test()
str input = "????????"
txt.print("\nCash: ")
util10.print_10s(ship10.cash)
txt.print("\nCommand (?=help): ")
ubyte num_chars = txt.input_chars(input)
txt.nl()
if num_chars {
when input[0] {
'?' -> {
txt.print("\nCommands are:\n"+
"buy jump info cash >=save\n"+
"sell teleport market10 hold <=load\n"+
"fuel galhyp local quit\n")
}
'q' -> break
'b' -> trader10.do_buy()
's' -> trader10.do_sell()
'f' -> trader10.do_fuel()
'j' -> trader10.do_jump()
't' -> trader10.do_teleport()
'g' -> trader10.do_next_galaxy10()
'i' -> trader10.do_info()
'm' -> trader10.do_show_market10()
'l' -> trader10.do_local()
'c' -> trader10.do_cash()
'h' -> trader10.do_hold()
'<' -> trader10.do_load()
'>' -> trader10.do_save()
}
}
}
}
}
trader10 {
str Savegame = "↑commander.save"
str input = "??????????"
ubyte num_chars
struct SaveData {
ubyte galaxy10
ubyte planet10
ubyte cargo0
ubyte cargo1
ubyte cargo2
ubyte cargo3
ubyte cargo4
ubyte cargo5
ubyte cargo6
ubyte cargo7
ubyte cargo8
ubyte cargo9
ubyte cargo10
ubyte cargo11
ubyte cargo12
ubyte cargo13
ubyte cargo14
ubyte cargo15
ubyte cargo16
uword cash
ubyte max_cargo
ubyte fuel
}
SaveData savedata
sub do_load() {
txt.print("\nLoading universe...")
if diskio.load(8, Savegame, &savedata) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
return
}
ship10.cash = savedata.cash
ship10.Max_cargo = savedata.max_cargo
ship10.fuel = savedata.fuel
sys.memcopy(&savedata.cargo0, ship10.cargohold, len(ship10.cargohold))
galaxy10.travel_to(savedata.galaxy10, savedata.planet10)
planet10.display(false)
}
sub do_save() {
savedata.galaxy10 = galaxy10.number
savedata.planet10 = planet10.number
savedata.cash = ship10.cash
savedata.max_cargo = ship10.Max_cargo
savedata.fuel = ship10.fuel
sys.memcopy(ship10.cargohold, &savedata.cargo0, len(ship10.cargohold))
txt.print("\nSaving universe...")
diskio.delete(8, Savegame)
if diskio.save(8, Savegame, &savedata, sizeof(savedata)) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
}
}
sub do_jump() {
txt.print("\nJump to what system? ")
jump_to_system()
}
sub do_teleport() {
txt.print("\nCheat! Teleport to what system? ")
ubyte fuel = ship10.fuel
ship10.fuel = 255
jump_to_system()
ship10.fuel = fuel
}
sub jump_to_system() {
void txt.input_chars(input)
ubyte current_planet10 = planet10.number
ubyte x = planet10.x
ubyte y = planet10.y
if galaxy10.search_closest_planet10(input) {
ubyte distance = planet10.distance(x, y)
if distance <= ship10.fuel {
galaxy10.init_market10_for_planet10()
ship10.fuel -= distance
txt.print("\n\nHyperspace jump! Arrived at:\n")
planet10.display(true)
return
}
txt.print("Insufficient fuel\n")
} else {
txt.print(" Not found!\n")
}
galaxy10.travel_to(galaxy10.number, current_planet10)
}
sub do_buy() {
txt.print("\nBuy what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market10.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if market10.current_quantity[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market10.current_price[ci] * amount
txt.print(" Total price: ")
util10.print_10s(price)
if price > ship10.cash {
txt.print(" Not enough cash!\n")
} else {
ship10.cash -= price
ship10.cargohold[ci] += amount
market10.current_quantity[ci] -= amount
}
}
}
}
sub do_sell() {
txt.print("\nSell what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market10.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if ship10.cargohold[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market10.current_price[ci] * amount
txt.print(" Total price: ")
util10.print_10s(price)
ship10.cash += price
ship10.cargohold[ci] -= amount
market10.current_quantity[ci] += amount
}
}
}
sub do_fuel() {
txt.print("\nBuy fuel. Amount? ")
void txt.input_chars(input)
ubyte buy_fuel = 10*conv.str2ubyte(input)
ubyte max_fuel = ship10.Max_fuel - ship10.fuel
if buy_fuel > max_fuel
buy_fuel = max_fuel
uword price = buy_fuel as uword * ship10.Fuel_cost
if price > ship10.cash {
txt.print("Not enough cash!\n")
} else {
ship10.cash -= price
ship10.fuel += buy_fuel
}
}
sub do_cash() {
txt.print("\nCheat! Set cash amount: ")
void txt.input_chars(input)
ship10.cash = conv.str2uword(input)
}
sub do_hold() {
txt.print("\nCheat! Set cargohold size: ")
void txt.input_chars(input)
ship10.Max_cargo = conv.str2ubyte(input)
}
sub do_next_galaxy10() {
galaxy10.travel_to(galaxy10.number+1, planet10.number)
planet10.display(false)
}
sub do_info() {
txt.print("\nSystem name (empty=current): ")
num_chars = txt.input_chars(input)
if num_chars {
ubyte current_planet10 = planet10.number
if galaxy10.search_closest_planet10(input) {
planet10.display(false)
} else {
txt.print(" Not found!")
}
galaxy10.travel_to(galaxy10.number, current_planet10)
} else {
planet10.display(false)
}
}
sub do_local() {
galaxy10.local_area()
}
sub do_show_market10() {
market10.display()
txt.print("\nFuel: ")
util10.print_10s(ship10.fuel)
txt.print(" Cargohold space: ")
txt.print_ub(ship10.cargo_free())
txt.print("t\n")
}
}
ship10 {
const ubyte Max_fuel = 70
const ubyte Fuel_cost = 2
ubyte Max_cargo = 20
ubyte fuel = Max_fuel
uword cash = 1000 ; actually has to be 4 bytes for the ultra rich....
ubyte[17] cargohold = 0
sub init() {
sys.memset(cargohold, len(cargohold), 0)
}
sub cargo_free() -> ubyte {
ubyte ci
ubyte total = 0
for ci in 0 to len(cargohold)-1 {
if market10.units[ci]==0 ; tonnes only
total += cargohold[ci]
}
return Max_cargo - total
}
}
market10 {
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
ubyte[17] units = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0]
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
ubyte[17] current_quantity = 0
uword[17] current_price = 0
sub init(ubyte fluct) {
; Prices and availabilities are influenced by the planet10's economy type
; (0-7) and a random "fluctuation" byte that was kept within the saved
; commander position to keep the market10 prices constant over gamesaves.
; Availabilities must be saved with the game since the player alters them
; by buying (and selling(?))
;
; Almost all operations are one byte only and overflow "errors" are
; extremely frequent and exploited.
;
; Trade Item prices are held internally in a single byte=true value/4.
; The decimal point in prices is introduced only when printing them.
; Internally, all prices are integers.
; The player's cash is held in four bytes.
ubyte ci
for ci in 0 to len(names)-1 {
word product
byte changing
product = planet10.economy as word * gradients[ci]
changing = fluct & maskbytes[ci] as byte
ubyte q = (basequants[ci] as word + changing - product) as ubyte
if q & $80
q = 0 ; clip to positive 8-bit
current_quantity[ci] = q & $3f
q = (baseprices[ci] + changing + product) as ubyte
current_price[ci] = q * $0004
}
current_quantity[16] = 0 ; force nonavailability of Alien Items
}
sub display() {
ubyte ci
txt.nl()
planet10.print_name_uppercase()
txt.print(" trade market10:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
for ci in 0 to len(names)-1 {
util10.print_right(13, names[ci])
txt.print(" ")
util10.print_10s(current_price[ci])
txt.print(" ")
txt.print_ub(current_quantity[ci])
when units[ci] {
0 -> txt.chrout('t')
1 -> txt.print("kg")
2 -> txt.chrout('g')
}
txt.print(" ")
txt.print_ub(ship10.cargohold[ci])
txt.nl()
}
}
sub match(uword nameptr) -> ubyte {
ubyte ci
for ci in 0 to len(names)-1 {
if util10.prefix_matches(nameptr, names[ci])
return ci
}
return 255
}
}
galaxy10 {
const uword GALSIZE = 256
const uword base0 = $5A4A ; seeds for the first galaxy10
const uword base1 = $0248
const uword base2 = $B753
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
ubyte number
uword[3] seed
sub init(ubyte galaxy10num) {
number = 1
planet10.number = 255
seed[0] = base0
seed[1] = base1
seed[2] = base2
repeat galaxy10num-1 {
nextgalaxy10()
}
}
sub nextgalaxy10() {
seed[0] = twist(seed[0])
seed[1] = twist(seed[1])
seed[2] = twist(seed[2])
number++
if number==9
number = 1
}
sub travel_to(ubyte galaxy10num, ubyte system) {
init(galaxy10num)
generate_next_planet10() ; always at least planet10 0 (separate to avoid repeat ubyte overflow)
repeat system {
generate_next_planet10()
}
planet10.name = make_current_planet10_name()
init_market10_for_planet10()
}
sub init_market10_for_planet10() {
market10.init(lsb(seed[0])+msb(seed[2]))
}
sub search_closest_planet10(uword nameptr) -> ubyte {
ubyte x = planet10.x
ubyte y = planet10.y
ubyte current_planet10_num = planet10.number
init(number)
ubyte found = false
ubyte current_closest_pi
ubyte current_distance = 127
ubyte pi
for pi in 0 to 255 {
generate_next_planet10()
planet10.name = make_current_planet10_name()
if util10.prefix_matches(nameptr, planet10.name) {
ubyte distance = planet10.distance(x, y)
if distance < current_distance {
current_distance = distance
current_closest_pi = pi
found = true
}
}
}
if found
travel_to(number, current_closest_pi)
else
travel_to(number, current_planet10_num)
return found
}
sub local_area() {
ubyte current_planet10 = planet10.number
ubyte px = planet10.x
ubyte py = planet10.y
ubyte pn = 0
init(number)
txt.print("\nGalaxy #")
txt.print_ub(number)
txt.print(" - systems in vicinity:\n")
do {
generate_next_planet10()
ubyte distance = planet10.distance(px, py)
if distance <= ship10.Max_fuel {
if distance <= ship10.fuel
txt.chrout('*')
else
txt.chrout('-')
txt.spc()
planet10.name = make_current_planet10_name()
planet10.display(true)
txt.print(" (")
util10.print_10s(distance)
txt.print(" LY)\n")
}
pn++
} until pn==0
travel_to(number, current_planet10)
}
ubyte pn_pair1
ubyte pn_pair2
ubyte pn_pair3
ubyte pn_pair4
ubyte longname
sub generate_next_planet10() {
determine_planet10_properties()
longname = lsb(seed[0]) & 64
; Always four iterations of random number
pn_pair1 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair2 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair3 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair4 = (msb(seed[2]) & 31) * 2
tweakseed()
}
sub make_current_planet10_name() -> str {
ubyte ni = 0
str name = " " ; max 8
if pn_pairs[pn_pair1] != '.' {
name[ni] = pn_pairs[pn_pair1]
ni++
}
if pn_pairs[pn_pair1+1] != '.' {
name[ni] = pn_pairs[pn_pair1+1]
ni++
}
if pn_pairs[pn_pair2] != '.' {
name[ni] = pn_pairs[pn_pair2]
ni++
}
if pn_pairs[pn_pair2+1] != '.' {
name[ni] = pn_pairs[pn_pair2+1]
ni++
}
if pn_pairs[pn_pair3] != '.' {
name[ni] = pn_pairs[pn_pair3]
ni++
}
if pn_pairs[pn_pair3+1] != '.' {
name[ni] = pn_pairs[pn_pair3+1]
ni++
}
if longname {
if pn_pairs[pn_pair4] != '.' {
name[ni] = pn_pairs[pn_pair4]
ni++
}
if pn_pairs[pn_pair4+1] != '.' {
name[ni] = pn_pairs[pn_pair4+1]
ni++
}
}
name[ni] = 0
return name
}
sub determine_planet10_properties() {
; create the planet10's characteristics
planet10.number++
planet10.x = msb(seed[1])
planet10.y = msb(seed[0])
planet10.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
planet10.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
if planet10.govtype <= 1
planet10.economy = (planet10.economy | 2)
planet10.techlevel = (msb(seed[1]) & 3) + (planet10.economy ^ 7)
planet10.techlevel += planet10.govtype >> 1
if planet10.govtype & 1
planet10.techlevel++
planet10.population = 4 * planet10.techlevel + planet10.economy
planet10.population += planet10.govtype + 1
planet10.productivity = ((planet10.economy ^ 7) + 3) * (planet10.govtype + 4)
planet10.productivity *= planet10.population * 8
ubyte seed2_msb = msb(seed[2])
planet10.radius = mkword((seed2_msb & 15) + 11, planet10.x)
planet10.species_is_alien = lsb(seed[2]) & 128 ; bit 7 of w2_lo
if planet10.species_is_alien {
planet10.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
planet10.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
planet10.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
planet10.species_kind = (planet10.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
}
planet10.goatsoup_seed[0] = lsb(seed[1])
planet10.goatsoup_seed[1] = msb(seed[1])
planet10.goatsoup_seed[2] = lsb(seed[2])
planet10.goatsoup_seed[3] = seed2_msb
}
sub tweakseed() {
uword temp = seed[0] + seed[1] + seed[2]
seed[0] = seed[1]
seed[1] = seed[2]
seed[2] = temp
}
sub twist(uword x) -> uword {
ubyte xh = msb(x)
ubyte xl = lsb(x)
rol(xh)
rol(xl)
return mkword(xh, xl)
}
sub debug_seed() {
txt.print("\ngalaxy10 #")
txt.print_ub(number)
txt.print("\ngalaxy10 seed0=")
txt.print_uwhex(galaxy10.seed[0], true)
txt.print("\ngalaxy10 seed1=")
txt.print_uwhex(galaxy10.seed[1], true)
txt.print("\ngalaxy10 seed2=")
txt.print_uwhex(galaxy10.seed[2], true)
txt.nl()
}
}
planet10 {
%option force_output
str[] species_sizes = ["Large", "Fierce", "Small"]
str[] species_colors = ["Green", "Red", "Yellow", "Blue", "Black", "Harmless"]
str[] species_looks = ["Slimy", "Bug-Eyed", "Horned", "Bony", "Fat", "Furry"]
str[] species_kinds = ["Rodents", "Frogs", "Lizards", "Lobsters", "Birds", "Humanoids", "Felines", "Insects"]
str[] govnames = ["Anarchy", "Feudal", "Multi-gov", "Dictatorship10", "Communist", "Confederacy", "Democracy", "Corporate State"]
str[] econnames = ["Rich Industrial", "Average Industrial", "Poor Industrial", "Mainly Industrial",
"Mainly Agricultural", "Rich Agricultural", "Average Agricultural", "Poor Agricultural"]
str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
str[] words82 = ["very", "mildly", "most", "reasonably", ""]
str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
str[] words8F = ["\xB0", "The planet10 \xB0", "The world \xB0", "This planet10", "This world"]
str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
str[] words91 = ["planet10", "world", "place", "little planet10", "dump"]
str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
uword[] wordlists = [
words81, words82, words83, words84, words85, words86, words87, words88,
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
words91, words92, words93, words94, words95, words96, words97, words98,
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
wordsA1, wordsA2, wordsA3, wordsA4]
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
str name = " " ; 8 max
ubyte number ; starts at 0 in new galaxy10, then increases by 1 for each generated planet10
ubyte x
ubyte y
ubyte economy
ubyte govtype
ubyte techlevel
ubyte population
uword productivity
uword radius
ubyte species_is_alien ; otherwise "Human Colonials"
ubyte species_size
ubyte species_color
ubyte species_look
ubyte species_kind
sub set_seed(uword s1, uword s2) {
goatsoup_seed[0] = lsb(s1)
goatsoup_seed[1] = msb(s1)
goatsoup_seed[2] = lsb(s2)
goatsoup_seed[3] = msb(s2)
reset_rnd()
}
sub reset_rnd() {
goatsoup_rnd[0] = goatsoup_seed[0]
goatsoup_rnd[1] = goatsoup_seed[1]
goatsoup_rnd[2] = goatsoup_seed[2]
goatsoup_rnd[3] = goatsoup_seed[3]
}
sub random_name() -> str {
ubyte ii
str name = " " ; 8 chars max
ubyte nx = 0
for ii in 0 to goatsoup_rnd_number() & 3 {
ubyte x = goatsoup_rnd_number() & $3e
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
x++
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
}
name[nx] = 0
name[0] |= 32 ; uppercase first letter
return name
}
sub goatsoup_rnd_number() -> ubyte {
ubyte x = goatsoup_rnd[0] * 2
uword a = x as uword + goatsoup_rnd[2]
if goatsoup_rnd[0] > 127
a ++
goatsoup_rnd[0] = lsb(a)
goatsoup_rnd[2] = x
x = goatsoup_rnd[1]
ubyte ac = x + goatsoup_rnd[3] + msb(a)
goatsoup_rnd[1] = ac
goatsoup_rnd[3] = x
return ac
}
sub distance(ubyte px, ubyte py) -> ubyte {
uword ax
uword ay
if px>x
ax=px-x
else
ax=x-px
if py>y
ay=py-y
else
ay=y-py
ay /= 2
ubyte d = sqrt16(ax*ax + ay*ay)
if d>63
return 255
return d*4
}
sub soup() -> str {
str planet10_result = " " * 160
uword[6] source_stack
ubyte stack_ptr = 0
str start_source = "\x8F is \x97."
uword source_ptr = &start_source
uword result_ptr = &planet10_result
reset_rnd()
recursive_soup()
return planet10_result
sub recursive_soup() {
repeat {
ubyte c = @(source_ptr)
source_ptr++
if c == $00 {
@(result_ptr) = 0
return
}
else if c <= $80 {
@(result_ptr) = c
result_ptr++
}
else {
if c <= $a4 {
ubyte rnr = goatsoup_rnd_number()
ubyte wordNr = (rnr >= $33) + (rnr >= $66) + (rnr >= $99) + (rnr >= $CC)
source_stack[stack_ptr] = source_ptr
stack_ptr++
source_ptr = getword(c, wordNr)
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
stack_ptr--
source_ptr = source_stack[stack_ptr]
} else {
if c == $b0 {
@(result_ptr) = name[0] | 32
result_ptr++
concat_string(&name + 1)
}
else if c == $b1 {
@(result_ptr) = name[0] | 32
result_ptr++
ubyte ni
for ni in 1 to len(name) {
ubyte cc = name[ni]
if cc=='e' or cc=='o' or cc==0
break
else {
@(result_ptr) = cc
result_ptr++
}
}
@(result_ptr) = 'i'
result_ptr++
@(result_ptr) = 'a'
result_ptr++
@(result_ptr) = 'n'
result_ptr++
}
else if c == $b2 {
concat_string(random_name())
}
else {
@(result_ptr) = c
result_ptr++
}
}
}
}
}
sub concat_string(uword str_ptr) {
repeat {
ubyte c = @(str_ptr)
if c==0
break
else {
@(result_ptr) = c
str_ptr++
result_ptr++
}
}
}
}
sub display(ubyte compressed) {
if compressed {
print_name_uppercase()
txt.print(" TL:")
txt.print_ub(techlevel+1)
txt.spc()
txt.print(econnames[economy])
txt.spc()
txt.print(govnames[govtype])
} else {
txt.print("\n\nSystem: ")
print_name_uppercase()
txt.print("\nPosition: ")
txt.print_ub(x)
txt.chrout('\'')
txt.print_ub(y)
txt.spc()
txt.chrout('#')
txt.print_ub(number)
txt.print("\nEconomy: ")
txt.print(econnames[economy])
txt.print("\nGovernment: ")
txt.print(govnames[govtype])
txt.print("\nTech Level: ")
txt.print_ub(techlevel+1)
txt.print("\nTurnover: ")
txt.print_uw(productivity)
txt.print("\nRadius: ")
txt.print_uw(radius)
txt.print("\nPopulation: ")
txt.print_ub(population >> 3)
txt.print(" Billion\nSpecies: ")
if species_is_alien {
if species_size < len(species_sizes) {
txt.print(species_sizes[species_size])
txt.spc()
}
if species_color < len(species_colors) {
txt.print(species_colors[species_color])
txt.spc()
}
if species_look < len(species_looks) {
txt.print(species_looks[species_look])
txt.spc()
}
if species_kind < len(species_kinds) {
txt.print(species_kinds[species_kind])
}
} else {
txt.print("Human Colonials")
}
txt.nl()
txt.print(soup())
txt.nl()
}
}
sub print_name_uppercase() {
ubyte c
for c in name
txt.chrout(c | 32)
}
asmsub getword(ubyte list @A, ubyte wordidx @Y) -> uword @AY {
%asm {{
sty P8ZP_SCRATCH_REG
sec
sbc #$81
asl a
tay
lda wordlists,y
sta P8ZP_SCRATCH_W1
lda wordlists+1,y
sta P8ZP_SCRATCH_W1+1
lda P8ZP_SCRATCH_REG
asl a
tay
lda (P8ZP_SCRATCH_W1),y
pha
iny
lda (P8ZP_SCRATCH_W1),y
tay
pla
rts
}}
}
}
util10 {
sub prefix_matches(uword prefixptr, uword stringptr) -> ubyte {
repeat {
ubyte pc = @(prefixptr)
ubyte sc = @(stringptr)
if pc == 0
return true
; to lowercase for case insensitive compare:
pc &= 127
sc &= 127
if pc != sc
return false
prefixptr++
stringptr++
}
return false
}
sub print_right(ubyte width, uword st) {
repeat width - string.length(st) {
txt.spc()
}
txt.print(st)
}
asmsub print_10s(uword value @AY) clobbers(A, X, Y) {
%asm {{
jsr conv.uword2decimal
lda conv.uword2decimal.decTenThousands
ldy #0 ; have we started printing?
cmp #'0'
beq +
jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decThousands
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decHundreds
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decTens
jsr c64.CHROUT
lda #'.'
jsr c64.CHROUT
lda conv.uword2decimal.decOnes
jsr c64.CHROUT
rts
}}
}
}

View File

@ -1,994 +0,0 @@
%import textio
%import conv
%import diskio
%import string
%import test_stack
%option no_sysinit
%zeropage basicsafe
; Prog8 adaptation of the Text-Elite galaxy2 system trading simulation engine.
; Original C-version obtained from: http://www.elitehomepage.org/text/index.htm
; Note: this program is compatible with C64 and CX16.
perf2 {
const ubyte numforLave = 7 ; Lave is 7th generated planet2 in galaxy2 one
const ubyte numforZaonce = 129
const ubyte numforDiso = 147
const ubyte numforRiedquat = 46
sub start() {
txt.lowercase()
txt.print("\u000c\n --- TextElite v1.1 ---\n")
galaxy2.travel_to(1, numforLave)
market2.init(0) ; Lave's market2 is seeded with 0
ship2.init()
planet2.display(false)
repeat {
; test_stack.test()
str input = "????????"
txt.print("\nCash: ")
util2.print_10s(ship2.cash)
txt.print("\nCommand (?=help): ")
ubyte num_chars = txt.input_chars(input)
txt.nl()
if num_chars {
when input[0] {
'?' -> {
txt.print("\nCommands are:\n"+
"buy jump info cash >=save\n"+
"sell teleport market2 hold <=load\n"+
"fuel galhyp local quit\n")
}
'q' -> break
'b' -> trader2.do_buy()
's' -> trader2.do_sell()
'f' -> trader2.do_fuel()
'j' -> trader2.do_jump()
't' -> trader2.do_teleport()
'g' -> trader2.do_next_galaxy2()
'i' -> trader2.do_info()
'm' -> trader2.do_show_market2()
'l' -> trader2.do_local()
'c' -> trader2.do_cash()
'h' -> trader2.do_hold()
'<' -> trader2.do_load()
'>' -> trader2.do_save()
}
}
}
}
}
trader2 {
str Savegame = "↑commander.save"
str input = "??????????"
ubyte num_chars
struct SaveData {
ubyte galaxy2
ubyte planet2
ubyte cargo0
ubyte cargo1
ubyte cargo2
ubyte cargo3
ubyte cargo4
ubyte cargo5
ubyte cargo6
ubyte cargo7
ubyte cargo8
ubyte cargo9
ubyte cargo10
ubyte cargo11
ubyte cargo12
ubyte cargo13
ubyte cargo14
ubyte cargo15
ubyte cargo16
uword cash
ubyte max_cargo
ubyte fuel
}
SaveData savedata
sub do_load() {
txt.print("\nLoading universe...")
if diskio.load(8, Savegame, &savedata) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
return
}
ship2.cash = savedata.cash
ship2.Max_cargo = savedata.max_cargo
ship2.fuel = savedata.fuel
sys.memcopy(&savedata.cargo0, ship2.cargohold, len(ship2.cargohold))
galaxy2.travel_to(savedata.galaxy2, savedata.planet2)
planet2.display(false)
}
sub do_save() {
savedata.galaxy2 = galaxy2.number
savedata.planet2 = planet2.number
savedata.cash = ship2.cash
savedata.max_cargo = ship2.Max_cargo
savedata.fuel = ship2.fuel
sys.memcopy(ship2.cargohold, &savedata.cargo0, len(ship2.cargohold))
txt.print("\nSaving universe...")
diskio.delete(8, Savegame)
if diskio.save(8, Savegame, &savedata, sizeof(savedata)) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
}
}
sub do_jump() {
txt.print("\nJump to what system? ")
jump_to_system()
}
sub do_teleport() {
txt.print("\nCheat! Teleport to what system? ")
ubyte fuel = ship2.fuel
ship2.fuel = 255
jump_to_system()
ship2.fuel = fuel
}
sub jump_to_system() {
void txt.input_chars(input)
ubyte current_planet2 = planet2.number
ubyte x = planet2.x
ubyte y = planet2.y
if galaxy2.search_closest_planet2(input) {
ubyte distance = planet2.distance(x, y)
if distance <= ship2.fuel {
galaxy2.init_market2_for_planet2()
ship2.fuel -= distance
txt.print("\n\nHyperspace jump! Arrived at:\n")
planet2.display(true)
return
}
txt.print("Insufficient fuel\n")
} else {
txt.print(" Not found!\n")
}
galaxy2.travel_to(galaxy2.number, current_planet2)
}
sub do_buy() {
txt.print("\nBuy what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market2.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if market2.current_quantity[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market2.current_price[ci] * amount
txt.print(" Total price: ")
util2.print_10s(price)
if price > ship2.cash {
txt.print(" Not enough cash!\n")
} else {
ship2.cash -= price
ship2.cargohold[ci] += amount
market2.current_quantity[ci] -= amount
}
}
}
}
sub do_sell() {
txt.print("\nSell what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market2.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if ship2.cargohold[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market2.current_price[ci] * amount
txt.print(" Total price: ")
util2.print_10s(price)
ship2.cash += price
ship2.cargohold[ci] -= amount
market2.current_quantity[ci] += amount
}
}
}
sub do_fuel() {
txt.print("\nBuy fuel. Amount? ")
void txt.input_chars(input)
ubyte buy_fuel = 10*conv.str2ubyte(input)
ubyte max_fuel = ship2.Max_fuel - ship2.fuel
if buy_fuel > max_fuel
buy_fuel = max_fuel
uword price = buy_fuel as uword * ship2.Fuel_cost
if price > ship2.cash {
txt.print("Not enough cash!\n")
} else {
ship2.cash -= price
ship2.fuel += buy_fuel
}
}
sub do_cash() {
txt.print("\nCheat! Set cash amount: ")
void txt.input_chars(input)
ship2.cash = conv.str2uword(input)
}
sub do_hold() {
txt.print("\nCheat! Set cargohold size: ")
void txt.input_chars(input)
ship2.Max_cargo = conv.str2ubyte(input)
}
sub do_next_galaxy2() {
galaxy2.travel_to(galaxy2.number+1, planet2.number)
planet2.display(false)
}
sub do_info() {
txt.print("\nSystem name (empty=current): ")
num_chars = txt.input_chars(input)
if num_chars {
ubyte current_planet2 = planet2.number
if galaxy2.search_closest_planet2(input) {
planet2.display(false)
} else {
txt.print(" Not found!")
}
galaxy2.travel_to(galaxy2.number, current_planet2)
} else {
planet2.display(false)
}
}
sub do_local() {
galaxy2.local_area()
}
sub do_show_market2() {
market2.display()
txt.print("\nFuel: ")
util2.print_10s(ship2.fuel)
txt.print(" Cargohold space: ")
txt.print_ub(ship2.cargo_free())
txt.print("t\n")
}
}
ship2 {
const ubyte Max_fuel = 70
const ubyte Fuel_cost = 2
ubyte Max_cargo = 20
ubyte fuel = Max_fuel
uword cash = 1000 ; actually has to be 4 bytes for the ultra rich....
ubyte[17] cargohold = 0
sub init() {
sys.memset(cargohold, len(cargohold), 0)
}
sub cargo_free() -> ubyte {
ubyte ci
ubyte total = 0
for ci in 0 to len(cargohold)-1 {
if market2.units[ci]==0 ; tonnes only
total += cargohold[ci]
}
return Max_cargo - total
}
}
market2 {
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
ubyte[17] units = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0]
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
ubyte[17] current_quantity = 0
uword[17] current_price = 0
sub init(ubyte fluct) {
; Prices and availabilities are influenced by the planet2's economy type
; (0-7) and a random "fluctuation" byte that was kept within the saved
; commander position to keep the market2 prices constant over gamesaves.
; Availabilities must be saved with the game since the player alters them
; by buying (and selling(?))
;
; Almost all operations are one byte only and overflow "errors" are
; extremely frequent and exploited.
;
; Trade Item prices are held internally in a single byte=true value/4.
; The decimal point in prices is introduced only when printing them.
; Internally, all prices are integers.
; The player's cash is held in four bytes.
ubyte ci
for ci in 0 to len(names)-1 {
word product
byte changing
product = planet2.economy as word * gradients[ci]
changing = fluct & maskbytes[ci] as byte
ubyte q = (basequants[ci] as word + changing - product) as ubyte
if q & $80
q = 0 ; clip to positive 8-bit
current_quantity[ci] = q & $3f
q = (baseprices[ci] + changing + product) as ubyte
current_price[ci] = q * $0004
}
current_quantity[16] = 0 ; force nonavailability of Alien Items
}
sub display() {
ubyte ci
txt.nl()
planet2.print_name_uppercase()
txt.print(" trade market2:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
for ci in 0 to len(names)-1 {
util2.print_right(13, names[ci])
txt.print(" ")
util2.print_10s(current_price[ci])
txt.print(" ")
txt.print_ub(current_quantity[ci])
when units[ci] {
0 -> txt.chrout('t')
1 -> txt.print("kg")
2 -> txt.chrout('g')
}
txt.print(" ")
txt.print_ub(ship2.cargohold[ci])
txt.nl()
}
}
sub match(uword nameptr) -> ubyte {
ubyte ci
for ci in 0 to len(names)-1 {
if util2.prefix_matches(nameptr, names[ci])
return ci
}
return 255
}
}
galaxy2 {
const uword GALSIZE = 256
const uword base0 = $5A4A ; seeds for the first galaxy2
const uword base1 = $0248
const uword base2 = $B753
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
ubyte number
uword[3] seed
sub init(ubyte galaxy2num) {
number = 1
planet2.number = 255
seed[0] = base0
seed[1] = base1
seed[2] = base2
repeat galaxy2num-1 {
nextgalaxy2()
}
}
sub nextgalaxy2() {
seed[0] = twist(seed[0])
seed[1] = twist(seed[1])
seed[2] = twist(seed[2])
number++
if number==9
number = 1
}
sub travel_to(ubyte galaxy2num, ubyte system) {
init(galaxy2num)
generate_next_planet2() ; always at least planet2 0 (separate to avoid repeat ubyte overflow)
repeat system {
generate_next_planet2()
}
planet2.name = make_current_planet2_name()
init_market2_for_planet2()
}
sub init_market2_for_planet2() {
market2.init(lsb(seed[0])+msb(seed[2]))
}
sub search_closest_planet2(uword nameptr) -> ubyte {
ubyte x = planet2.x
ubyte y = planet2.y
ubyte current_planet2_num = planet2.number
init(number)
ubyte found = false
ubyte current_closest_pi
ubyte current_distance = 127
ubyte pi
for pi in 0 to 255 {
generate_next_planet2()
planet2.name = make_current_planet2_name()
if util2.prefix_matches(nameptr, planet2.name) {
ubyte distance = planet2.distance(x, y)
if distance < current_distance {
current_distance = distance
current_closest_pi = pi
found = true
}
}
}
if found
travel_to(number, current_closest_pi)
else
travel_to(number, current_planet2_num)
return found
}
sub local_area() {
ubyte current_planet2 = planet2.number
ubyte px = planet2.x
ubyte py = planet2.y
ubyte pn = 0
init(number)
txt.print("\nGalaxy #")
txt.print_ub(number)
txt.print(" - systems in vicinity:\n")
do {
generate_next_planet2()
ubyte distance = planet2.distance(px, py)
if distance <= ship2.Max_fuel {
if distance <= ship2.fuel
txt.chrout('*')
else
txt.chrout('-')
txt.spc()
planet2.name = make_current_planet2_name()
planet2.display(true)
txt.print(" (")
util2.print_10s(distance)
txt.print(" LY)\n")
}
pn++
} until pn==0
travel_to(number, current_planet2)
}
ubyte pn_pair1
ubyte pn_pair2
ubyte pn_pair3
ubyte pn_pair4
ubyte longname
sub generate_next_planet2() {
determine_planet2_properties()
longname = lsb(seed[0]) & 64
; Always four iterations of random number
pn_pair1 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair2 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair3 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair4 = (msb(seed[2]) & 31) * 2
tweakseed()
}
sub make_current_planet2_name() -> str {
ubyte ni = 0
str name = " " ; max 8
if pn_pairs[pn_pair1] != '.' {
name[ni] = pn_pairs[pn_pair1]
ni++
}
if pn_pairs[pn_pair1+1] != '.' {
name[ni] = pn_pairs[pn_pair1+1]
ni++
}
if pn_pairs[pn_pair2] != '.' {
name[ni] = pn_pairs[pn_pair2]
ni++
}
if pn_pairs[pn_pair2+1] != '.' {
name[ni] = pn_pairs[pn_pair2+1]
ni++
}
if pn_pairs[pn_pair3] != '.' {
name[ni] = pn_pairs[pn_pair3]
ni++
}
if pn_pairs[pn_pair3+1] != '.' {
name[ni] = pn_pairs[pn_pair3+1]
ni++
}
if longname {
if pn_pairs[pn_pair4] != '.' {
name[ni] = pn_pairs[pn_pair4]
ni++
}
if pn_pairs[pn_pair4+1] != '.' {
name[ni] = pn_pairs[pn_pair4+1]
ni++
}
}
name[ni] = 0
return name
}
sub determine_planet2_properties() {
; create the planet2's characteristics
planet2.number++
planet2.x = msb(seed[1])
planet2.y = msb(seed[0])
planet2.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
planet2.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
if planet2.govtype <= 1
planet2.economy = (planet2.economy | 2)
planet2.techlevel = (msb(seed[1]) & 3) + (planet2.economy ^ 7)
planet2.techlevel += planet2.govtype >> 1
if planet2.govtype & 1
planet2.techlevel++
planet2.population = 4 * planet2.techlevel + planet2.economy
planet2.population += planet2.govtype + 1
planet2.productivity = ((planet2.economy ^ 7) + 3) * (planet2.govtype + 4)
planet2.productivity *= planet2.population * 8
ubyte seed2_msb = msb(seed[2])
planet2.radius = mkword((seed2_msb & 15) + 11, planet2.x)
planet2.species_is_alien = lsb(seed[2]) & 128 ; bit 7 of w2_lo
if planet2.species_is_alien {
planet2.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
planet2.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
planet2.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
planet2.species_kind = (planet2.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
}
planet2.goatsoup_seed[0] = lsb(seed[1])
planet2.goatsoup_seed[1] = msb(seed[1])
planet2.goatsoup_seed[2] = lsb(seed[2])
planet2.goatsoup_seed[3] = seed2_msb
}
sub tweakseed() {
uword temp = seed[0] + seed[1] + seed[2]
seed[0] = seed[1]
seed[1] = seed[2]
seed[2] = temp
}
sub twist(uword x) -> uword {
ubyte xh = msb(x)
ubyte xl = lsb(x)
rol(xh)
rol(xl)
return mkword(xh, xl)
}
sub debug_seed() {
txt.print("\ngalaxy2 #")
txt.print_ub(number)
txt.print("\ngalaxy2 seed0=")
txt.print_uwhex(galaxy2.seed[0], true)
txt.print("\ngalaxy2 seed1=")
txt.print_uwhex(galaxy2.seed[1], true)
txt.print("\ngalaxy2 seed2=")
txt.print_uwhex(galaxy2.seed[2], true)
txt.nl()
}
}
planet2 {
%option force_output
str[] species_sizes = ["Large", "Fierce", "Small"]
str[] species_colors = ["Green", "Red", "Yellow", "Blue", "Black", "Harmless"]
str[] species_looks = ["Slimy", "Bug-Eyed", "Horned", "Bony", "Fat", "Furry"]
str[] species_kinds = ["Rodents", "Frogs", "Lizards", "Lobsters", "Birds", "Humanoids", "Felines", "Insects"]
str[] govnames = ["Anarchy", "Feudal", "Multi-gov", "Dictatorship2", "Communist", "Confederacy", "Democracy", "Corporate State"]
str[] econnames = ["Rich Industrial", "Average Industrial", "Poor Industrial", "Mainly Industrial",
"Mainly Agricultural", "Rich Agricultural", "Average Agricultural", "Poor Agricultural"]
str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
str[] words82 = ["very", "mildly", "most", "reasonably", ""]
str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
str[] words8F = ["\xB0", "The planet2 \xB0", "The world \xB0", "This planet2", "This world"]
str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
str[] words91 = ["planet2", "world", "place", "little planet2", "dump"]
str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
uword[] wordlists = [
words81, words82, words83, words84, words85, words86, words87, words88,
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
words91, words92, words93, words94, words95, words96, words97, words98,
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
wordsA1, wordsA2, wordsA3, wordsA4]
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
str name = " " ; 8 max
ubyte number ; starts at 0 in new galaxy2, then increases by 1 for each generated planet2
ubyte x
ubyte y
ubyte economy
ubyte govtype
ubyte techlevel
ubyte population
uword productivity
uword radius
ubyte species_is_alien ; otherwise "Human Colonials"
ubyte species_size
ubyte species_color
ubyte species_look
ubyte species_kind
sub set_seed(uword s1, uword s2) {
goatsoup_seed[0] = lsb(s1)
goatsoup_seed[1] = msb(s1)
goatsoup_seed[2] = lsb(s2)
goatsoup_seed[3] = msb(s2)
reset_rnd()
}
sub reset_rnd() {
goatsoup_rnd[0] = goatsoup_seed[0]
goatsoup_rnd[1] = goatsoup_seed[1]
goatsoup_rnd[2] = goatsoup_seed[2]
goatsoup_rnd[3] = goatsoup_seed[3]
}
sub random_name() -> str {
ubyte ii
str name = " " ; 8 chars max
ubyte nx = 0
for ii in 0 to goatsoup_rnd_number() & 3 {
ubyte x = goatsoup_rnd_number() & $3e
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
x++
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
}
name[nx] = 0
name[0] |= 32 ; uppercase first letter
return name
}
sub goatsoup_rnd_number() -> ubyte {
ubyte x = goatsoup_rnd[0] * 2
uword a = x as uword + goatsoup_rnd[2]
if goatsoup_rnd[0] > 127
a ++
goatsoup_rnd[0] = lsb(a)
goatsoup_rnd[2] = x
x = goatsoup_rnd[1]
ubyte ac = x + goatsoup_rnd[3] + msb(a)
goatsoup_rnd[1] = ac
goatsoup_rnd[3] = x
return ac
}
sub distance(ubyte px, ubyte py) -> ubyte {
uword ax
uword ay
if px>x
ax=px-x
else
ax=x-px
if py>y
ay=py-y
else
ay=y-py
ay /= 2
ubyte d = sqrt16(ax*ax + ay*ay)
if d>63
return 255
return d*4
}
sub soup() -> str {
str planet2_result = " " * 160
uword[6] source_stack
ubyte stack_ptr = 0
str start_source = "\x8F is \x97."
uword source_ptr = &start_source
uword result_ptr = &planet2_result
reset_rnd()
recursive_soup()
return planet2_result
sub recursive_soup() {
repeat {
ubyte c = @(source_ptr)
source_ptr++
if c == $00 {
@(result_ptr) = 0
return
}
else if c <= $80 {
@(result_ptr) = c
result_ptr++
}
else {
if c <= $a4 {
ubyte rnr = goatsoup_rnd_number()
ubyte wordNr = (rnr >= $33) + (rnr >= $66) + (rnr >= $99) + (rnr >= $CC)
source_stack[stack_ptr] = source_ptr
stack_ptr++
source_ptr = getword(c, wordNr)
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
stack_ptr--
source_ptr = source_stack[stack_ptr]
} else {
if c == $b0 {
@(result_ptr) = name[0] | 32
result_ptr++
concat_string(&name + 1)
}
else if c == $b1 {
@(result_ptr) = name[0] | 32
result_ptr++
ubyte ni
for ni in 1 to len(name) {
ubyte cc = name[ni]
if cc=='e' or cc=='o' or cc==0
break
else {
@(result_ptr) = cc
result_ptr++
}
}
@(result_ptr) = 'i'
result_ptr++
@(result_ptr) = 'a'
result_ptr++
@(result_ptr) = 'n'
result_ptr++
}
else if c == $b2 {
concat_string(random_name())
}
else {
@(result_ptr) = c
result_ptr++
}
}
}
}
}
sub concat_string(uword str_ptr) {
repeat {
ubyte c = @(str_ptr)
if c==0
break
else {
@(result_ptr) = c
str_ptr++
result_ptr++
}
}
}
}
sub display(ubyte compressed) {
if compressed {
print_name_uppercase()
txt.print(" TL:")
txt.print_ub(techlevel+1)
txt.spc()
txt.print(econnames[economy])
txt.spc()
txt.print(govnames[govtype])
} else {
txt.print("\n\nSystem: ")
print_name_uppercase()
txt.print("\nPosition: ")
txt.print_ub(x)
txt.chrout('\'')
txt.print_ub(y)
txt.spc()
txt.chrout('#')
txt.print_ub(number)
txt.print("\nEconomy: ")
txt.print(econnames[economy])
txt.print("\nGovernment: ")
txt.print(govnames[govtype])
txt.print("\nTech Level: ")
txt.print_ub(techlevel+1)
txt.print("\nTurnover: ")
txt.print_uw(productivity)
txt.print("\nRadius: ")
txt.print_uw(radius)
txt.print("\nPopulation: ")
txt.print_ub(population >> 3)
txt.print(" Billion\nSpecies: ")
if species_is_alien {
if species_size < len(species_sizes) {
txt.print(species_sizes[species_size])
txt.spc()
}
if species_color < len(species_colors) {
txt.print(species_colors[species_color])
txt.spc()
}
if species_look < len(species_looks) {
txt.print(species_looks[species_look])
txt.spc()
}
if species_kind < len(species_kinds) {
txt.print(species_kinds[species_kind])
}
} else {
txt.print("Human Colonials")
}
txt.nl()
txt.print(soup())
txt.nl()
}
}
sub print_name_uppercase() {
ubyte c
for c in name
txt.chrout(c | 32)
}
asmsub getword(ubyte list @A, ubyte wordidx @Y) -> uword @AY {
%asm {{
sty P8ZP_SCRATCH_REG
sec
sbc #$81
asl a
tay
lda wordlists,y
sta P8ZP_SCRATCH_W1
lda wordlists+1,y
sta P8ZP_SCRATCH_W1+1
lda P8ZP_SCRATCH_REG
asl a
tay
lda (P8ZP_SCRATCH_W1),y
pha
iny
lda (P8ZP_SCRATCH_W1),y
tay
pla
rts
}}
}
}
util2 {
sub prefix_matches(uword prefixptr, uword stringptr) -> ubyte {
repeat {
ubyte pc = @(prefixptr)
ubyte sc = @(stringptr)
if pc == 0
return true
; to lowercase for case insensitive compare:
pc &= 127
sc &= 127
if pc != sc
return false
prefixptr++
stringptr++
}
return false
}
sub print_right(ubyte width, uword st) {
repeat width - string.length(st) {
txt.spc()
}
txt.print(st)
}
asmsub print_10s(uword value @AY) clobbers(A, X, Y) {
%asm {{
jsr conv.uword2decimal
lda conv.uword2decimal.decTenThousands
ldy #0 ; have we started printing?
cmp #'0'
beq +
jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decThousands
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decHundreds
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decTens
jsr c64.CHROUT
lda #'.'
jsr c64.CHROUT
lda conv.uword2decimal.decOnes
jsr c64.CHROUT
rts
}}
}
}

View File

@ -1,994 +0,0 @@
%import textio
%import conv
%import diskio
%import string
%import test_stack
%option no_sysinit
%zeropage basicsafe
; Prog8 adaptation of the Text-Elite galaxy3 system trading simulation engine.
; Original C-version obtained from: http://www.elitehomepage.org/text/index.htm
; Note: this program is compatible with C64 and CX16.
perf3 {
const ubyte numforLave = 7 ; Lave is 7th generated planet3 in galaxy3 one
const ubyte numforZaonce = 129
const ubyte numforDiso = 147
const ubyte numforRiedquat = 46
sub start() {
txt.lowercase()
txt.print("\u000c\n --- TextElite v1.1 ---\n")
galaxy3.travel_to(1, numforLave)
market3.init(0) ; Lave's market3 is seeded with 0
ship3.init()
planet3.display(false)
repeat {
; test_stack.test()
str input = "????????"
txt.print("\nCash: ")
util3.print_10s(ship3.cash)
txt.print("\nCommand (?=help): ")
ubyte num_chars = txt.input_chars(input)
txt.nl()
if num_chars {
when input[0] {
'?' -> {
txt.print("\nCommands are:\n"+
"buy jump info cash >=save\n"+
"sell teleport market3 hold <=load\n"+
"fuel galhyp local quit\n")
}
'q' -> break
'b' -> trader3.do_buy()
's' -> trader3.do_sell()
'f' -> trader3.do_fuel()
'j' -> trader3.do_jump()
't' -> trader3.do_teleport()
'g' -> trader3.do_next_galaxy3()
'i' -> trader3.do_info()
'm' -> trader3.do_show_market3()
'l' -> trader3.do_local()
'c' -> trader3.do_cash()
'h' -> trader3.do_hold()
'<' -> trader3.do_load()
'>' -> trader3.do_save()
}
}
}
}
}
trader3 {
str Savegame = "↑commander.save"
str input = "??????????"
ubyte num_chars
struct SaveData {
ubyte galaxy3
ubyte planet3
ubyte cargo0
ubyte cargo1
ubyte cargo2
ubyte cargo3
ubyte cargo4
ubyte cargo5
ubyte cargo6
ubyte cargo7
ubyte cargo8
ubyte cargo9
ubyte cargo10
ubyte cargo11
ubyte cargo12
ubyte cargo13
ubyte cargo14
ubyte cargo15
ubyte cargo16
uword cash
ubyte max_cargo
ubyte fuel
}
SaveData savedata
sub do_load() {
txt.print("\nLoading universe...")
if diskio.load(8, Savegame, &savedata) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
return
}
ship3.cash = savedata.cash
ship3.Max_cargo = savedata.max_cargo
ship3.fuel = savedata.fuel
sys.memcopy(&savedata.cargo0, ship3.cargohold, len(ship3.cargohold))
galaxy3.travel_to(savedata.galaxy3, savedata.planet3)
planet3.display(false)
}
sub do_save() {
savedata.galaxy3 = galaxy3.number
savedata.planet3 = planet3.number
savedata.cash = ship3.cash
savedata.max_cargo = ship3.Max_cargo
savedata.fuel = ship3.fuel
sys.memcopy(ship3.cargohold, &savedata.cargo0, len(ship3.cargohold))
txt.print("\nSaving universe...")
diskio.delete(8, Savegame)
if diskio.save(8, Savegame, &savedata, sizeof(savedata)) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
}
}
sub do_jump() {
txt.print("\nJump to what system? ")
jump_to_system()
}
sub do_teleport() {
txt.print("\nCheat! Teleport to what system? ")
ubyte fuel = ship3.fuel
ship3.fuel = 255
jump_to_system()
ship3.fuel = fuel
}
sub jump_to_system() {
void txt.input_chars(input)
ubyte current_planet3 = planet3.number
ubyte x = planet3.x
ubyte y = planet3.y
if galaxy3.search_closest_planet3(input) {
ubyte distance = planet3.distance(x, y)
if distance <= ship3.fuel {
galaxy3.init_market3_for_planet3()
ship3.fuel -= distance
txt.print("\n\nHyperspace jump! Arrived at:\n")
planet3.display(true)
return
}
txt.print("Insufficient fuel\n")
} else {
txt.print(" Not found!\n")
}
galaxy3.travel_to(galaxy3.number, current_planet3)
}
sub do_buy() {
txt.print("\nBuy what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market3.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if market3.current_quantity[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market3.current_price[ci] * amount
txt.print(" Total price: ")
util3.print_10s(price)
if price > ship3.cash {
txt.print(" Not enough cash!\n")
} else {
ship3.cash -= price
ship3.cargohold[ci] += amount
market3.current_quantity[ci] -= amount
}
}
}
}
sub do_sell() {
txt.print("\nSell what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market3.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if ship3.cargohold[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market3.current_price[ci] * amount
txt.print(" Total price: ")
util3.print_10s(price)
ship3.cash += price
ship3.cargohold[ci] -= amount
market3.current_quantity[ci] += amount
}
}
}
sub do_fuel() {
txt.print("\nBuy fuel. Amount? ")
void txt.input_chars(input)
ubyte buy_fuel = 10*conv.str2ubyte(input)
ubyte max_fuel = ship3.Max_fuel - ship3.fuel
if buy_fuel > max_fuel
buy_fuel = max_fuel
uword price = buy_fuel as uword * ship3.Fuel_cost
if price > ship3.cash {
txt.print("Not enough cash!\n")
} else {
ship3.cash -= price
ship3.fuel += buy_fuel
}
}
sub do_cash() {
txt.print("\nCheat! Set cash amount: ")
void txt.input_chars(input)
ship3.cash = conv.str2uword(input)
}
sub do_hold() {
txt.print("\nCheat! Set cargohold size: ")
void txt.input_chars(input)
ship3.Max_cargo = conv.str2ubyte(input)
}
sub do_next_galaxy3() {
galaxy3.travel_to(galaxy3.number+1, planet3.number)
planet3.display(false)
}
sub do_info() {
txt.print("\nSystem name (empty=current): ")
num_chars = txt.input_chars(input)
if num_chars {
ubyte current_planet3 = planet3.number
if galaxy3.search_closest_planet3(input) {
planet3.display(false)
} else {
txt.print(" Not found!")
}
galaxy3.travel_to(galaxy3.number, current_planet3)
} else {
planet3.display(false)
}
}
sub do_local() {
galaxy3.local_area()
}
sub do_show_market3() {
market3.display()
txt.print("\nFuel: ")
util3.print_10s(ship3.fuel)
txt.print(" Cargohold space: ")
txt.print_ub(ship3.cargo_free())
txt.print("t\n")
}
}
ship3 {
const ubyte Max_fuel = 70
const ubyte Fuel_cost = 2
ubyte Max_cargo = 20
ubyte fuel = Max_fuel
uword cash = 1000 ; actually has to be 4 bytes for the ultra rich....
ubyte[17] cargohold = 0
sub init() {
sys.memset(cargohold, len(cargohold), 0)
}
sub cargo_free() -> ubyte {
ubyte ci
ubyte total = 0
for ci in 0 to len(cargohold)-1 {
if market3.units[ci]==0 ; tonnes only
total += cargohold[ci]
}
return Max_cargo - total
}
}
market3 {
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
ubyte[17] units = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0]
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
ubyte[17] current_quantity = 0
uword[17] current_price = 0
sub init(ubyte fluct) {
; Prices and availabilities are influenced by the planet3's economy type
; (0-7) and a random "fluctuation" byte that was kept within the saved
; commander position to keep the market3 prices constant over gamesaves.
; Availabilities must be saved with the game since the player alters them
; by buying (and selling(?))
;
; Almost all operations are one byte only and overflow "errors" are
; extremely frequent and exploited.
;
; Trade Item prices are held internally in a single byte=true value/4.
; The decimal point in prices is introduced only when printing them.
; Internally, all prices are integers.
; The player's cash is held in four bytes.
ubyte ci
for ci in 0 to len(names)-1 {
word product
byte changing
product = planet3.economy as word * gradients[ci]
changing = fluct & maskbytes[ci] as byte
ubyte q = (basequants[ci] as word + changing - product) as ubyte
if q & $80
q = 0 ; clip to positive 8-bit
current_quantity[ci] = q & $3f
q = (baseprices[ci] + changing + product) as ubyte
current_price[ci] = q * $0004
}
current_quantity[16] = 0 ; force nonavailability of Alien Items
}
sub display() {
ubyte ci
txt.nl()
planet3.print_name_uppercase()
txt.print(" trade market3:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
for ci in 0 to len(names)-1 {
util3.print_right(13, names[ci])
txt.print(" ")
util3.print_10s(current_price[ci])
txt.print(" ")
txt.print_ub(current_quantity[ci])
when units[ci] {
0 -> txt.chrout('t')
1 -> txt.print("kg")
2 -> txt.chrout('g')
}
txt.print(" ")
txt.print_ub(ship3.cargohold[ci])
txt.nl()
}
}
sub match(uword nameptr) -> ubyte {
ubyte ci
for ci in 0 to len(names)-1 {
if util3.prefix_matches(nameptr, names[ci])
return ci
}
return 255
}
}
galaxy3 {
const uword GALSIZE = 256
const uword base0 = $5A4A ; seeds for the first galaxy3
const uword base1 = $0248
const uword base2 = $B753
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
ubyte number
uword[3] seed
sub init(ubyte galaxy3num) {
number = 1
planet3.number = 255
seed[0] = base0
seed[1] = base1
seed[2] = base2
repeat galaxy3num-1 {
nextgalaxy3()
}
}
sub nextgalaxy3() {
seed[0] = twist(seed[0])
seed[1] = twist(seed[1])
seed[2] = twist(seed[2])
number++
if number==9
number = 1
}
sub travel_to(ubyte galaxy3num, ubyte system) {
init(galaxy3num)
generate_next_planet3() ; always at least planet3 0 (separate to avoid repeat ubyte overflow)
repeat system {
generate_next_planet3()
}
planet3.name = make_current_planet3_name()
init_market3_for_planet3()
}
sub init_market3_for_planet3() {
market3.init(lsb(seed[0])+msb(seed[2]))
}
sub search_closest_planet3(uword nameptr) -> ubyte {
ubyte x = planet3.x
ubyte y = planet3.y
ubyte current_planet3_num = planet3.number
init(number)
ubyte found = false
ubyte current_closest_pi
ubyte current_distance = 127
ubyte pi
for pi in 0 to 255 {
generate_next_planet3()
planet3.name = make_current_planet3_name()
if util3.prefix_matches(nameptr, planet3.name) {
ubyte distance = planet3.distance(x, y)
if distance < current_distance {
current_distance = distance
current_closest_pi = pi
found = true
}
}
}
if found
travel_to(number, current_closest_pi)
else
travel_to(number, current_planet3_num)
return found
}
sub local_area() {
ubyte current_planet3 = planet3.number
ubyte px = planet3.x
ubyte py = planet3.y
ubyte pn = 0
init(number)
txt.print("\nGalaxy #")
txt.print_ub(number)
txt.print(" - systems in vicinity:\n")
do {
generate_next_planet3()
ubyte distance = planet3.distance(px, py)
if distance <= ship3.Max_fuel {
if distance <= ship3.fuel
txt.chrout('*')
else
txt.chrout('-')
txt.spc()
planet3.name = make_current_planet3_name()
planet3.display(true)
txt.print(" (")
util3.print_10s(distance)
txt.print(" LY)\n")
}
pn++
} until pn==0
travel_to(number, current_planet3)
}
ubyte pn_pair1
ubyte pn_pair2
ubyte pn_pair3
ubyte pn_pair4
ubyte longname
sub generate_next_planet3() {
determine_planet3_properties()
longname = lsb(seed[0]) & 64
; Always four iterations of random number
pn_pair1 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair2 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair3 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair4 = (msb(seed[2]) & 31) * 2
tweakseed()
}
sub make_current_planet3_name() -> str {
ubyte ni = 0
str name = " " ; max 8
if pn_pairs[pn_pair1] != '.' {
name[ni] = pn_pairs[pn_pair1]
ni++
}
if pn_pairs[pn_pair1+1] != '.' {
name[ni] = pn_pairs[pn_pair1+1]
ni++
}
if pn_pairs[pn_pair2] != '.' {
name[ni] = pn_pairs[pn_pair2]
ni++
}
if pn_pairs[pn_pair2+1] != '.' {
name[ni] = pn_pairs[pn_pair2+1]
ni++
}
if pn_pairs[pn_pair3] != '.' {
name[ni] = pn_pairs[pn_pair3]
ni++
}
if pn_pairs[pn_pair3+1] != '.' {
name[ni] = pn_pairs[pn_pair3+1]
ni++
}
if longname {
if pn_pairs[pn_pair4] != '.' {
name[ni] = pn_pairs[pn_pair4]
ni++
}
if pn_pairs[pn_pair4+1] != '.' {
name[ni] = pn_pairs[pn_pair4+1]
ni++
}
}
name[ni] = 0
return name
}
sub determine_planet3_properties() {
; create the planet3's characteristics
planet3.number++
planet3.x = msb(seed[1])
planet3.y = msb(seed[0])
planet3.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
planet3.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
if planet3.govtype <= 1
planet3.economy = (planet3.economy | 2)
planet3.techlevel = (msb(seed[1]) & 3) + (planet3.economy ^ 7)
planet3.techlevel += planet3.govtype >> 1
if planet3.govtype & 1
planet3.techlevel++
planet3.population = 4 * planet3.techlevel + planet3.economy
planet3.population += planet3.govtype + 1
planet3.productivity = ((planet3.economy ^ 7) + 3) * (planet3.govtype + 4)
planet3.productivity *= planet3.population * 8
ubyte seed2_msb = msb(seed[2])
planet3.radius = mkword((seed2_msb & 15) + 11, planet3.x)
planet3.species_is_alien = lsb(seed[2]) & 128 ; bit 7 of w2_lo
if planet3.species_is_alien {
planet3.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
planet3.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
planet3.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
planet3.species_kind = (planet3.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
}
planet3.goatsoup_seed[0] = lsb(seed[1])
planet3.goatsoup_seed[1] = msb(seed[1])
planet3.goatsoup_seed[2] = lsb(seed[2])
planet3.goatsoup_seed[3] = seed2_msb
}
sub tweakseed() {
uword temp = seed[0] + seed[1] + seed[2]
seed[0] = seed[1]
seed[1] = seed[2]
seed[2] = temp
}
sub twist(uword x) -> uword {
ubyte xh = msb(x)
ubyte xl = lsb(x)
rol(xh)
rol(xl)
return mkword(xh, xl)
}
sub debug_seed() {
txt.print("\ngalaxy3 #")
txt.print_ub(number)
txt.print("\ngalaxy3 seed0=")
txt.print_uwhex(galaxy3.seed[0], true)
txt.print("\ngalaxy3 seed1=")
txt.print_uwhex(galaxy3.seed[1], true)
txt.print("\ngalaxy3 seed2=")
txt.print_uwhex(galaxy3.seed[2], true)
txt.nl()
}
}
planet3 {
%option force_output
str[] species_sizes = ["Large", "Fierce", "Small"]
str[] species_colors = ["Green", "Red", "Yellow", "Blue", "Black", "Harmless"]
str[] species_looks = ["Slimy", "Bug-Eyed", "Horned", "Bony", "Fat", "Furry"]
str[] species_kinds = ["Rodents", "Frogs", "Lizards", "Lobsters", "Birds", "Humanoids", "Felines", "Insects"]
str[] govnames = ["Anarchy", "Feudal", "Multi-gov", "Dictatorship3", "Communist", "Confederacy", "Democracy", "Corporate State"]
str[] econnames = ["Rich Industrial", "Average Industrial", "Poor Industrial", "Mainly Industrial",
"Mainly Agricultural", "Rich Agricultural", "Average Agricultural", "Poor Agricultural"]
str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
str[] words82 = ["very", "mildly", "most", "reasonably", ""]
str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
str[] words8F = ["\xB0", "The planet3 \xB0", "The world \xB0", "This planet3", "This world"]
str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
str[] words91 = ["planet3", "world", "place", "little planet3", "dump"]
str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
uword[] wordlists = [
words81, words82, words83, words84, words85, words86, words87, words88,
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
words91, words92, words93, words94, words95, words96, words97, words98,
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
wordsA1, wordsA2, wordsA3, wordsA4]
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
str name = " " ; 8 max
ubyte number ; starts at 0 in new galaxy3, then increases by 1 for each generated planet3
ubyte x
ubyte y
ubyte economy
ubyte govtype
ubyte techlevel
ubyte population
uword productivity
uword radius
ubyte species_is_alien ; otherwise "Human Colonials"
ubyte species_size
ubyte species_color
ubyte species_look
ubyte species_kind
sub set_seed(uword s1, uword s2) {
goatsoup_seed[0] = lsb(s1)
goatsoup_seed[1] = msb(s1)
goatsoup_seed[2] = lsb(s2)
goatsoup_seed[3] = msb(s2)
reset_rnd()
}
sub reset_rnd() {
goatsoup_rnd[0] = goatsoup_seed[0]
goatsoup_rnd[1] = goatsoup_seed[1]
goatsoup_rnd[2] = goatsoup_seed[2]
goatsoup_rnd[3] = goatsoup_seed[3]
}
sub random_name() -> str {
ubyte ii
str name = " " ; 8 chars max
ubyte nx = 0
for ii in 0 to goatsoup_rnd_number() & 3 {
ubyte x = goatsoup_rnd_number() & $3e
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
x++
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
}
name[nx] = 0
name[0] |= 32 ; uppercase first letter
return name
}
sub goatsoup_rnd_number() -> ubyte {
ubyte x = goatsoup_rnd[0] * 2
uword a = x as uword + goatsoup_rnd[2]
if goatsoup_rnd[0] > 127
a ++
goatsoup_rnd[0] = lsb(a)
goatsoup_rnd[2] = x
x = goatsoup_rnd[1]
ubyte ac = x + goatsoup_rnd[3] + msb(a)
goatsoup_rnd[1] = ac
goatsoup_rnd[3] = x
return ac
}
sub distance(ubyte px, ubyte py) -> ubyte {
uword ax
uword ay
if px>x
ax=px-x
else
ax=x-px
if py>y
ay=py-y
else
ay=y-py
ay /= 2
ubyte d = sqrt16(ax*ax + ay*ay)
if d>63
return 255
return d*4
}
sub soup() -> str {
str planet3_result = " " * 160
uword[6] source_stack
ubyte stack_ptr = 0
str start_source = "\x8F is \x97."
uword source_ptr = &start_source
uword result_ptr = &planet3_result
reset_rnd()
recursive_soup()
return planet3_result
sub recursive_soup() {
repeat {
ubyte c = @(source_ptr)
source_ptr++
if c == $00 {
@(result_ptr) = 0
return
}
else if c <= $80 {
@(result_ptr) = c
result_ptr++
}
else {
if c <= $a4 {
ubyte rnr = goatsoup_rnd_number()
ubyte wordNr = (rnr >= $33) + (rnr >= $66) + (rnr >= $99) + (rnr >= $CC)
source_stack[stack_ptr] = source_ptr
stack_ptr++
source_ptr = getword(c, wordNr)
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
stack_ptr--
source_ptr = source_stack[stack_ptr]
} else {
if c == $b0 {
@(result_ptr) = name[0] | 32
result_ptr++
concat_string(&name + 1)
}
else if c == $b1 {
@(result_ptr) = name[0] | 32
result_ptr++
ubyte ni
for ni in 1 to len(name) {
ubyte cc = name[ni]
if cc=='e' or cc=='o' or cc==0
break
else {
@(result_ptr) = cc
result_ptr++
}
}
@(result_ptr) = 'i'
result_ptr++
@(result_ptr) = 'a'
result_ptr++
@(result_ptr) = 'n'
result_ptr++
}
else if c == $b2 {
concat_string(random_name())
}
else {
@(result_ptr) = c
result_ptr++
}
}
}
}
}
sub concat_string(uword str_ptr) {
repeat {
ubyte c = @(str_ptr)
if c==0
break
else {
@(result_ptr) = c
str_ptr++
result_ptr++
}
}
}
}
sub display(ubyte compressed) {
if compressed {
print_name_uppercase()
txt.print(" TL:")
txt.print_ub(techlevel+1)
txt.spc()
txt.print(econnames[economy])
txt.spc()
txt.print(govnames[govtype])
} else {
txt.print("\n\nSystem: ")
print_name_uppercase()
txt.print("\nPosition: ")
txt.print_ub(x)
txt.chrout('\'')
txt.print_ub(y)
txt.spc()
txt.chrout('#')
txt.print_ub(number)
txt.print("\nEconomy: ")
txt.print(econnames[economy])
txt.print("\nGovernment: ")
txt.print(govnames[govtype])
txt.print("\nTech Level: ")
txt.print_ub(techlevel+1)
txt.print("\nTurnover: ")
txt.print_uw(productivity)
txt.print("\nRadius: ")
txt.print_uw(radius)
txt.print("\nPopulation: ")
txt.print_ub(population >> 3)
txt.print(" Billion\nSpecies: ")
if species_is_alien {
if species_size < len(species_sizes) {
txt.print(species_sizes[species_size])
txt.spc()
}
if species_color < len(species_colors) {
txt.print(species_colors[species_color])
txt.spc()
}
if species_look < len(species_looks) {
txt.print(species_looks[species_look])
txt.spc()
}
if species_kind < len(species_kinds) {
txt.print(species_kinds[species_kind])
}
} else {
txt.print("Human Colonials")
}
txt.nl()
txt.print(soup())
txt.nl()
}
}
sub print_name_uppercase() {
ubyte c
for c in name
txt.chrout(c | 32)
}
asmsub getword(ubyte list @A, ubyte wordidx @Y) -> uword @AY {
%asm {{
sty P8ZP_SCRATCH_REG
sec
sbc #$81
asl a
tay
lda wordlists,y
sta P8ZP_SCRATCH_W1
lda wordlists+1,y
sta P8ZP_SCRATCH_W1+1
lda P8ZP_SCRATCH_REG
asl a
tay
lda (P8ZP_SCRATCH_W1),y
pha
iny
lda (P8ZP_SCRATCH_W1),y
tay
pla
rts
}}
}
}
util3 {
sub prefix_matches(uword prefixptr, uword stringptr) -> ubyte {
repeat {
ubyte pc = @(prefixptr)
ubyte sc = @(stringptr)
if pc == 0
return true
; to lowercase for case insensitive compare:
pc &= 127
sc &= 127
if pc != sc
return false
prefixptr++
stringptr++
}
return false
}
sub print_right(ubyte width, uword st) {
repeat width - string.length(st) {
txt.spc()
}
txt.print(st)
}
asmsub print_10s(uword value @AY) clobbers(A, X, Y) {
%asm {{
jsr conv.uword2decimal
lda conv.uword2decimal.decTenThousands
ldy #0 ; have we started printing?
cmp #'0'
beq +
jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decThousands
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decHundreds
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decTens
jsr c64.CHROUT
lda #'.'
jsr c64.CHROUT
lda conv.uword2decimal.decOnes
jsr c64.CHROUT
rts
}}
}
}

View File

@ -1,994 +0,0 @@
%import textio
%import conv
%import diskio
%import string
%import test_stack
%option no_sysinit
%zeropage basicsafe
; Prog8 adaptation of the Text-Elite galaxy4 system trading simulation engine.
; Original C-version obtained from: http://www.elitehomepage.org/text/index.htm
; Note: this program is compatible with C64 and CX16.
perf4 {
const ubyte numforLave = 7 ; Lave is 7th generated planet4 in galaxy4 one
const ubyte numforZaonce = 129
const ubyte numforDiso = 147
const ubyte numforRiedquat = 46
sub start() {
txt.lowercase()
txt.print("\u000c\n --- TextElite v1.1 ---\n")
galaxy4.travel_to(1, numforLave)
market4.init(0) ; Lave's market4 is seeded with 0
ship4.init()
planet4.display(false)
repeat {
; test_stack.test()
str input = "????????"
txt.print("\nCash: ")
util4.print_10s(ship4.cash)
txt.print("\nCommand (?=help): ")
ubyte num_chars = txt.input_chars(input)
txt.nl()
if num_chars {
when input[0] {
'?' -> {
txt.print("\nCommands are:\n"+
"buy jump info cash >=save\n"+
"sell teleport market4 hold <=load\n"+
"fuel galhyp local quit\n")
}
'q' -> break
'b' -> trader4.do_buy()
's' -> trader4.do_sell()
'f' -> trader4.do_fuel()
'j' -> trader4.do_jump()
't' -> trader4.do_teleport()
'g' -> trader4.do_next_galaxy4()
'i' -> trader4.do_info()
'm' -> trader4.do_show_market4()
'l' -> trader4.do_local()
'c' -> trader4.do_cash()
'h' -> trader4.do_hold()
'<' -> trader4.do_load()
'>' -> trader4.do_save()
}
}
}
}
}
trader4 {
str Savegame = "↑commander.save"
str input = "??????????"
ubyte num_chars
struct SaveData {
ubyte galaxy4
ubyte planet4
ubyte cargo0
ubyte cargo1
ubyte cargo2
ubyte cargo3
ubyte cargo4
ubyte cargo5
ubyte cargo6
ubyte cargo7
ubyte cargo8
ubyte cargo9
ubyte cargo10
ubyte cargo11
ubyte cargo12
ubyte cargo13
ubyte cargo14
ubyte cargo15
ubyte cargo16
uword cash
ubyte max_cargo
ubyte fuel
}
SaveData savedata
sub do_load() {
txt.print("\nLoading universe...")
if diskio.load(8, Savegame, &savedata) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
return
}
ship4.cash = savedata.cash
ship4.Max_cargo = savedata.max_cargo
ship4.fuel = savedata.fuel
sys.memcopy(&savedata.cargo0, ship4.cargohold, len(ship4.cargohold))
galaxy4.travel_to(savedata.galaxy4, savedata.planet4)
planet4.display(false)
}
sub do_save() {
savedata.galaxy4 = galaxy4.number
savedata.planet4 = planet4.number
savedata.cash = ship4.cash
savedata.max_cargo = ship4.Max_cargo
savedata.fuel = ship4.fuel
sys.memcopy(ship4.cargohold, &savedata.cargo0, len(ship4.cargohold))
txt.print("\nSaving universe...")
diskio.delete(8, Savegame)
if diskio.save(8, Savegame, &savedata, sizeof(savedata)) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
}
}
sub do_jump() {
txt.print("\nJump to what system? ")
jump_to_system()
}
sub do_teleport() {
txt.print("\nCheat! Teleport to what system? ")
ubyte fuel = ship4.fuel
ship4.fuel = 255
jump_to_system()
ship4.fuel = fuel
}
sub jump_to_system() {
void txt.input_chars(input)
ubyte current_planet4 = planet4.number
ubyte x = planet4.x
ubyte y = planet4.y
if galaxy4.search_closest_planet4(input) {
ubyte distance = planet4.distance(x, y)
if distance <= ship4.fuel {
galaxy4.init_market4_for_planet4()
ship4.fuel -= distance
txt.print("\n\nHyperspace jump! Arrived at:\n")
planet4.display(true)
return
}
txt.print("Insufficient fuel\n")
} else {
txt.print(" Not found!\n")
}
galaxy4.travel_to(galaxy4.number, current_planet4)
}
sub do_buy() {
txt.print("\nBuy what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market4.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if market4.current_quantity[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market4.current_price[ci] * amount
txt.print(" Total price: ")
util4.print_10s(price)
if price > ship4.cash {
txt.print(" Not enough cash!\n")
} else {
ship4.cash -= price
ship4.cargohold[ci] += amount
market4.current_quantity[ci] -= amount
}
}
}
}
sub do_sell() {
txt.print("\nSell what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market4.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if ship4.cargohold[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market4.current_price[ci] * amount
txt.print(" Total price: ")
util4.print_10s(price)
ship4.cash += price
ship4.cargohold[ci] -= amount
market4.current_quantity[ci] += amount
}
}
}
sub do_fuel() {
txt.print("\nBuy fuel. Amount? ")
void txt.input_chars(input)
ubyte buy_fuel = 10*conv.str2ubyte(input)
ubyte max_fuel = ship4.Max_fuel - ship4.fuel
if buy_fuel > max_fuel
buy_fuel = max_fuel
uword price = buy_fuel as uword * ship4.Fuel_cost
if price > ship4.cash {
txt.print("Not enough cash!\n")
} else {
ship4.cash -= price
ship4.fuel += buy_fuel
}
}
sub do_cash() {
txt.print("\nCheat! Set cash amount: ")
void txt.input_chars(input)
ship4.cash = conv.str2uword(input)
}
sub do_hold() {
txt.print("\nCheat! Set cargohold size: ")
void txt.input_chars(input)
ship4.Max_cargo = conv.str2ubyte(input)
}
sub do_next_galaxy4() {
galaxy4.travel_to(galaxy4.number+1, planet4.number)
planet4.display(false)
}
sub do_info() {
txt.print("\nSystem name (empty=current): ")
num_chars = txt.input_chars(input)
if num_chars {
ubyte current_planet4 = planet4.number
if galaxy4.search_closest_planet4(input) {
planet4.display(false)
} else {
txt.print(" Not found!")
}
galaxy4.travel_to(galaxy4.number, current_planet4)
} else {
planet4.display(false)
}
}
sub do_local() {
galaxy4.local_area()
}
sub do_show_market4() {
market4.display()
txt.print("\nFuel: ")
util4.print_10s(ship4.fuel)
txt.print(" Cargohold space: ")
txt.print_ub(ship4.cargo_free())
txt.print("t\n")
}
}
ship4 {
const ubyte Max_fuel = 70
const ubyte Fuel_cost = 2
ubyte Max_cargo = 20
ubyte fuel = Max_fuel
uword cash = 1000 ; actually has to be 4 bytes for the ultra rich....
ubyte[17] cargohold = 0
sub init() {
sys.memset(cargohold, len(cargohold), 0)
}
sub cargo_free() -> ubyte {
ubyte ci
ubyte total = 0
for ci in 0 to len(cargohold)-1 {
if market4.units[ci]==0 ; tonnes only
total += cargohold[ci]
}
return Max_cargo - total
}
}
market4 {
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
ubyte[17] units = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0]
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
ubyte[17] current_quantity = 0
uword[17] current_price = 0
sub init(ubyte fluct) {
; Prices and availabilities are influenced by the planet4's economy type
; (0-7) and a random "fluctuation" byte that was kept within the saved
; commander position to keep the market4 prices constant over gamesaves.
; Availabilities must be saved with the game since the player alters them
; by buying (and selling(?))
;
; Almost all operations are one byte only and overflow "errors" are
; extremely frequent and exploited.
;
; Trade Item prices are held internally in a single byte=true value/4.
; The decimal point in prices is introduced only when printing them.
; Internally, all prices are integers.
; The player's cash is held in four bytes.
ubyte ci
for ci in 0 to len(names)-1 {
word product
byte changing
product = planet4.economy as word * gradients[ci]
changing = fluct & maskbytes[ci] as byte
ubyte q = (basequants[ci] as word + changing - product) as ubyte
if q & $80
q = 0 ; clip to positive 8-bit
current_quantity[ci] = q & $3f
q = (baseprices[ci] + changing + product) as ubyte
current_price[ci] = q * $0004
}
current_quantity[16] = 0 ; force nonavailability of Alien Items
}
sub display() {
ubyte ci
txt.nl()
planet4.print_name_uppercase()
txt.print(" trade market4:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
for ci in 0 to len(names)-1 {
util4.print_right(13, names[ci])
txt.print(" ")
util4.print_10s(current_price[ci])
txt.print(" ")
txt.print_ub(current_quantity[ci])
when units[ci] {
0 -> txt.chrout('t')
1 -> txt.print("kg")
2 -> txt.chrout('g')
}
txt.print(" ")
txt.print_ub(ship4.cargohold[ci])
txt.nl()
}
}
sub match(uword nameptr) -> ubyte {
ubyte ci
for ci in 0 to len(names)-1 {
if util4.prefix_matches(nameptr, names[ci])
return ci
}
return 255
}
}
galaxy4 {
const uword GALSIZE = 256
const uword base0 = $5A4A ; seeds for the first galaxy4
const uword base1 = $0248
const uword base2 = $B753
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
ubyte number
uword[3] seed
sub init(ubyte galaxy4num) {
number = 1
planet4.number = 255
seed[0] = base0
seed[1] = base1
seed[2] = base2
repeat galaxy4num-1 {
nextgalaxy4()
}
}
sub nextgalaxy4() {
seed[0] = twist(seed[0])
seed[1] = twist(seed[1])
seed[2] = twist(seed[2])
number++
if number==9
number = 1
}
sub travel_to(ubyte galaxy4num, ubyte system) {
init(galaxy4num)
generate_next_planet4() ; always at least planet4 0 (separate to avoid repeat ubyte overflow)
repeat system {
generate_next_planet4()
}
planet4.name = make_current_planet4_name()
init_market4_for_planet4()
}
sub init_market4_for_planet4() {
market4.init(lsb(seed[0])+msb(seed[2]))
}
sub search_closest_planet4(uword nameptr) -> ubyte {
ubyte x = planet4.x
ubyte y = planet4.y
ubyte current_planet4_num = planet4.number
init(number)
ubyte found = false
ubyte current_closest_pi
ubyte current_distance = 127
ubyte pi
for pi in 0 to 255 {
generate_next_planet4()
planet4.name = make_current_planet4_name()
if util4.prefix_matches(nameptr, planet4.name) {
ubyte distance = planet4.distance(x, y)
if distance < current_distance {
current_distance = distance
current_closest_pi = pi
found = true
}
}
}
if found
travel_to(number, current_closest_pi)
else
travel_to(number, current_planet4_num)
return found
}
sub local_area() {
ubyte current_planet4 = planet4.number
ubyte px = planet4.x
ubyte py = planet4.y
ubyte pn = 0
init(number)
txt.print("\nGalaxy #")
txt.print_ub(number)
txt.print(" - systems in vicinity:\n")
do {
generate_next_planet4()
ubyte distance = planet4.distance(px, py)
if distance <= ship4.Max_fuel {
if distance <= ship4.fuel
txt.chrout('*')
else
txt.chrout('-')
txt.spc()
planet4.name = make_current_planet4_name()
planet4.display(true)
txt.print(" (")
util4.print_10s(distance)
txt.print(" LY)\n")
}
pn++
} until pn==0
travel_to(number, current_planet4)
}
ubyte pn_pair1
ubyte pn_pair2
ubyte pn_pair3
ubyte pn_pair4
ubyte longname
sub generate_next_planet4() {
determine_planet4_properties()
longname = lsb(seed[0]) & 64
; Always four iterations of random number
pn_pair1 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair2 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair3 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair4 = (msb(seed[2]) & 31) * 2
tweakseed()
}
sub make_current_planet4_name() -> str {
ubyte ni = 0
str name = " " ; max 8
if pn_pairs[pn_pair1] != '.' {
name[ni] = pn_pairs[pn_pair1]
ni++
}
if pn_pairs[pn_pair1+1] != '.' {
name[ni] = pn_pairs[pn_pair1+1]
ni++
}
if pn_pairs[pn_pair2] != '.' {
name[ni] = pn_pairs[pn_pair2]
ni++
}
if pn_pairs[pn_pair2+1] != '.' {
name[ni] = pn_pairs[pn_pair2+1]
ni++
}
if pn_pairs[pn_pair3] != '.' {
name[ni] = pn_pairs[pn_pair3]
ni++
}
if pn_pairs[pn_pair3+1] != '.' {
name[ni] = pn_pairs[pn_pair3+1]
ni++
}
if longname {
if pn_pairs[pn_pair4] != '.' {
name[ni] = pn_pairs[pn_pair4]
ni++
}
if pn_pairs[pn_pair4+1] != '.' {
name[ni] = pn_pairs[pn_pair4+1]
ni++
}
}
name[ni] = 0
return name
}
sub determine_planet4_properties() {
; create the planet4's characteristics
planet4.number++
planet4.x = msb(seed[1])
planet4.y = msb(seed[0])
planet4.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
planet4.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
if planet4.govtype <= 1
planet4.economy = (planet4.economy | 2)
planet4.techlevel = (msb(seed[1]) & 3) + (planet4.economy ^ 7)
planet4.techlevel += planet4.govtype >> 1
if planet4.govtype & 1
planet4.techlevel++
planet4.population = 4 * planet4.techlevel + planet4.economy
planet4.population += planet4.govtype + 1
planet4.productivity = ((planet4.economy ^ 7) + 3) * (planet4.govtype + 4)
planet4.productivity *= planet4.population * 8
ubyte seed2_msb = msb(seed[2])
planet4.radius = mkword((seed2_msb & 15) + 11, planet4.x)
planet4.species_is_alien = lsb(seed[2]) & 128 ; bit 7 of w2_lo
if planet4.species_is_alien {
planet4.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
planet4.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
planet4.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
planet4.species_kind = (planet4.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
}
planet4.goatsoup_seed[0] = lsb(seed[1])
planet4.goatsoup_seed[1] = msb(seed[1])
planet4.goatsoup_seed[2] = lsb(seed[2])
planet4.goatsoup_seed[3] = seed2_msb
}
sub tweakseed() {
uword temp = seed[0] + seed[1] + seed[2]
seed[0] = seed[1]
seed[1] = seed[2]
seed[2] = temp
}
sub twist(uword x) -> uword {
ubyte xh = msb(x)
ubyte xl = lsb(x)
rol(xh)
rol(xl)
return mkword(xh, xl)
}
sub debug_seed() {
txt.print("\ngalaxy4 #")
txt.print_ub(number)
txt.print("\ngalaxy4 seed0=")
txt.print_uwhex(galaxy4.seed[0], true)
txt.print("\ngalaxy4 seed1=")
txt.print_uwhex(galaxy4.seed[1], true)
txt.print("\ngalaxy4 seed2=")
txt.print_uwhex(galaxy4.seed[2], true)
txt.nl()
}
}
planet4 {
%option force_output
str[] species_sizes = ["Large", "Fierce", "Small"]
str[] species_colors = ["Green", "Red", "Yellow", "Blue", "Black", "Harmless"]
str[] species_looks = ["Slimy", "Bug-Eyed", "Horned", "Bony", "Fat", "Furry"]
str[] species_kinds = ["Rodents", "Frogs", "Lizards", "Lobsters", "Birds", "Humanoids", "Felines", "Insects"]
str[] govnames = ["Anarchy", "Feudal", "Multi-gov", "Dictatorship4", "Communist", "Confederacy", "Democracy", "Corporate State"]
str[] econnames = ["Rich Industrial", "Average Industrial", "Poor Industrial", "Mainly Industrial",
"Mainly Agricultural", "Rich Agricultural", "Average Agricultural", "Poor Agricultural"]
str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
str[] words82 = ["very", "mildly", "most", "reasonably", ""]
str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
str[] words8F = ["\xB0", "The planet4 \xB0", "The world \xB0", "This planet4", "This world"]
str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
str[] words91 = ["planet4", "world", "place", "little planet4", "dump"]
str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
uword[] wordlists = [
words81, words82, words83, words84, words85, words86, words87, words88,
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
words91, words92, words93, words94, words95, words96, words97, words98,
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
wordsA1, wordsA2, wordsA3, wordsA4]
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
str name = " " ; 8 max
ubyte number ; starts at 0 in new galaxy4, then increases by 1 for each generated planet4
ubyte x
ubyte y
ubyte economy
ubyte govtype
ubyte techlevel
ubyte population
uword productivity
uword radius
ubyte species_is_alien ; otherwise "Human Colonials"
ubyte species_size
ubyte species_color
ubyte species_look
ubyte species_kind
sub set_seed(uword s1, uword s2) {
goatsoup_seed[0] = lsb(s1)
goatsoup_seed[1] = msb(s1)
goatsoup_seed[2] = lsb(s2)
goatsoup_seed[3] = msb(s2)
reset_rnd()
}
sub reset_rnd() {
goatsoup_rnd[0] = goatsoup_seed[0]
goatsoup_rnd[1] = goatsoup_seed[1]
goatsoup_rnd[2] = goatsoup_seed[2]
goatsoup_rnd[3] = goatsoup_seed[3]
}
sub random_name() -> str {
ubyte ii
str name = " " ; 8 chars max
ubyte nx = 0
for ii in 0 to goatsoup_rnd_number() & 3 {
ubyte x = goatsoup_rnd_number() & $3e
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
x++
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
}
name[nx] = 0
name[0] |= 32 ; uppercase first letter
return name
}
sub goatsoup_rnd_number() -> ubyte {
ubyte x = goatsoup_rnd[0] * 2
uword a = x as uword + goatsoup_rnd[2]
if goatsoup_rnd[0] > 127
a ++
goatsoup_rnd[0] = lsb(a)
goatsoup_rnd[2] = x
x = goatsoup_rnd[1]
ubyte ac = x + goatsoup_rnd[3] + msb(a)
goatsoup_rnd[1] = ac
goatsoup_rnd[3] = x
return ac
}
sub distance(ubyte px, ubyte py) -> ubyte {
uword ax
uword ay
if px>x
ax=px-x
else
ax=x-px
if py>y
ay=py-y
else
ay=y-py
ay /= 2
ubyte d = sqrt16(ax*ax + ay*ay)
if d>63
return 255
return d*4
}
sub soup() -> str {
str planet4_result = " " * 160
uword[6] source_stack
ubyte stack_ptr = 0
str start_source = "\x8F is \x97."
uword source_ptr = &start_source
uword result_ptr = &planet4_result
reset_rnd()
recursive_soup()
return planet4_result
sub recursive_soup() {
repeat {
ubyte c = @(source_ptr)
source_ptr++
if c == $00 {
@(result_ptr) = 0
return
}
else if c <= $80 {
@(result_ptr) = c
result_ptr++
}
else {
if c <= $a4 {
ubyte rnr = goatsoup_rnd_number()
ubyte wordNr = (rnr >= $33) + (rnr >= $66) + (rnr >= $99) + (rnr >= $CC)
source_stack[stack_ptr] = source_ptr
stack_ptr++
source_ptr = getword(c, wordNr)
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
stack_ptr--
source_ptr = source_stack[stack_ptr]
} else {
if c == $b0 {
@(result_ptr) = name[0] | 32
result_ptr++
concat_string(&name + 1)
}
else if c == $b1 {
@(result_ptr) = name[0] | 32
result_ptr++
ubyte ni
for ni in 1 to len(name) {
ubyte cc = name[ni]
if cc=='e' or cc=='o' or cc==0
break
else {
@(result_ptr) = cc
result_ptr++
}
}
@(result_ptr) = 'i'
result_ptr++
@(result_ptr) = 'a'
result_ptr++
@(result_ptr) = 'n'
result_ptr++
}
else if c == $b2 {
concat_string(random_name())
}
else {
@(result_ptr) = c
result_ptr++
}
}
}
}
}
sub concat_string(uword str_ptr) {
repeat {
ubyte c = @(str_ptr)
if c==0
break
else {
@(result_ptr) = c
str_ptr++
result_ptr++
}
}
}
}
sub display(ubyte compressed) {
if compressed {
print_name_uppercase()
txt.print(" TL:")
txt.print_ub(techlevel+1)
txt.spc()
txt.print(econnames[economy])
txt.spc()
txt.print(govnames[govtype])
} else {
txt.print("\n\nSystem: ")
print_name_uppercase()
txt.print("\nPosition: ")
txt.print_ub(x)
txt.chrout('\'')
txt.print_ub(y)
txt.spc()
txt.chrout('#')
txt.print_ub(number)
txt.print("\nEconomy: ")
txt.print(econnames[economy])
txt.print("\nGovernment: ")
txt.print(govnames[govtype])
txt.print("\nTech Level: ")
txt.print_ub(techlevel+1)
txt.print("\nTurnover: ")
txt.print_uw(productivity)
txt.print("\nRadius: ")
txt.print_uw(radius)
txt.print("\nPopulation: ")
txt.print_ub(population >> 3)
txt.print(" Billion\nSpecies: ")
if species_is_alien {
if species_size < len(species_sizes) {
txt.print(species_sizes[species_size])
txt.spc()
}
if species_color < len(species_colors) {
txt.print(species_colors[species_color])
txt.spc()
}
if species_look < len(species_looks) {
txt.print(species_looks[species_look])
txt.spc()
}
if species_kind < len(species_kinds) {
txt.print(species_kinds[species_kind])
}
} else {
txt.print("Human Colonials")
}
txt.nl()
txt.print(soup())
txt.nl()
}
}
sub print_name_uppercase() {
ubyte c
for c in name
txt.chrout(c | 32)
}
asmsub getword(ubyte list @A, ubyte wordidx @Y) -> uword @AY {
%asm {{
sty P8ZP_SCRATCH_REG
sec
sbc #$81
asl a
tay
lda wordlists,y
sta P8ZP_SCRATCH_W1
lda wordlists+1,y
sta P8ZP_SCRATCH_W1+1
lda P8ZP_SCRATCH_REG
asl a
tay
lda (P8ZP_SCRATCH_W1),y
pha
iny
lda (P8ZP_SCRATCH_W1),y
tay
pla
rts
}}
}
}
util4 {
sub prefix_matches(uword prefixptr, uword stringptr) -> ubyte {
repeat {
ubyte pc = @(prefixptr)
ubyte sc = @(stringptr)
if pc == 0
return true
; to lowercase for case insensitive compare:
pc &= 127
sc &= 127
if pc != sc
return false
prefixptr++
stringptr++
}
return false
}
sub print_right(ubyte width, uword st) {
repeat width - string.length(st) {
txt.spc()
}
txt.print(st)
}
asmsub print_10s(uword value @AY) clobbers(A, X, Y) {
%asm {{
jsr conv.uword2decimal
lda conv.uword2decimal.decTenThousands
ldy #0 ; have we started printing?
cmp #'0'
beq +
jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decThousands
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decHundreds
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decTens
jsr c64.CHROUT
lda #'.'
jsr c64.CHROUT
lda conv.uword2decimal.decOnes
jsr c64.CHROUT
rts
}}
}
}

View File

@ -1,994 +0,0 @@
%import textio
%import conv
%import diskio
%import string
%import test_stack
%option no_sysinit
%zeropage basicsafe
; Prog8 adaptation of the Text-Elite galaxy5 system trading simulation engine.
; Original C-version obtained from: http://www.elitehomepage.org/text/index.htm
; Note: this program is compatible with C64 and CX16.
perf5 {
const ubyte numforLave = 7 ; Lave is 7th generated planet5 in galaxy5 one
const ubyte numforZaonce = 129
const ubyte numforDiso = 147
const ubyte numforRiedquat = 46
sub start() {
txt.lowercase()
txt.print("\u000c\n --- TextElite v1.1 ---\n")
galaxy5.travel_to(1, numforLave)
market5.init(0) ; Lave's market5 is seeded with 0
ship5.init()
planet5.display(false)
repeat {
; test_stack.test()
str input = "????????"
txt.print("\nCash: ")
util5.print_10s(ship5.cash)
txt.print("\nCommand (?=help): ")
ubyte num_chars = txt.input_chars(input)
txt.nl()
if num_chars {
when input[0] {
'?' -> {
txt.print("\nCommands are:\n"+
"buy jump info cash >=save\n"+
"sell teleport market5 hold <=load\n"+
"fuel galhyp local quit\n")
}
'q' -> break
'b' -> trader5.do_buy()
's' -> trader5.do_sell()
'f' -> trader5.do_fuel()
'j' -> trader5.do_jump()
't' -> trader5.do_teleport()
'g' -> trader5.do_next_galaxy5()
'i' -> trader5.do_info()
'm' -> trader5.do_show_market5()
'l' -> trader5.do_local()
'c' -> trader5.do_cash()
'h' -> trader5.do_hold()
'<' -> trader5.do_load()
'>' -> trader5.do_save()
}
}
}
}
}
trader5 {
str Savegame = "↑commander.save"
str input = "??????????"
ubyte num_chars
struct SaveData {
ubyte galaxy5
ubyte planet5
ubyte cargo0
ubyte cargo1
ubyte cargo2
ubyte cargo3
ubyte cargo4
ubyte cargo5
ubyte cargo6
ubyte cargo7
ubyte cargo8
ubyte cargo9
ubyte cargo10
ubyte cargo11
ubyte cargo12
ubyte cargo13
ubyte cargo14
ubyte cargo15
ubyte cargo16
uword cash
ubyte max_cargo
ubyte fuel
}
SaveData savedata
sub do_load() {
txt.print("\nLoading universe...")
if diskio.load(8, Savegame, &savedata) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
return
}
ship5.cash = savedata.cash
ship5.Max_cargo = savedata.max_cargo
ship5.fuel = savedata.fuel
sys.memcopy(&savedata.cargo0, ship5.cargohold, len(ship5.cargohold))
galaxy5.travel_to(savedata.galaxy5, savedata.planet5)
planet5.display(false)
}
sub do_save() {
savedata.galaxy5 = galaxy5.number
savedata.planet5 = planet5.number
savedata.cash = ship5.cash
savedata.max_cargo = ship5.Max_cargo
savedata.fuel = ship5.fuel
sys.memcopy(ship5.cargohold, &savedata.cargo0, len(ship5.cargohold))
txt.print("\nSaving universe...")
diskio.delete(8, Savegame)
if diskio.save(8, Savegame, &savedata, sizeof(savedata)) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
}
}
sub do_jump() {
txt.print("\nJump to what system? ")
jump_to_system()
}
sub do_teleport() {
txt.print("\nCheat! Teleport to what system? ")
ubyte fuel = ship5.fuel
ship5.fuel = 255
jump_to_system()
ship5.fuel = fuel
}
sub jump_to_system() {
void txt.input_chars(input)
ubyte current_planet5 = planet5.number
ubyte x = planet5.x
ubyte y = planet5.y
if galaxy5.search_closest_planet5(input) {
ubyte distance = planet5.distance(x, y)
if distance <= ship5.fuel {
galaxy5.init_market5_for_planet5()
ship5.fuel -= distance
txt.print("\n\nHyperspace jump! Arrived at:\n")
planet5.display(true)
return
}
txt.print("Insufficient fuel\n")
} else {
txt.print(" Not found!\n")
}
galaxy5.travel_to(galaxy5.number, current_planet5)
}
sub do_buy() {
txt.print("\nBuy what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market5.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if market5.current_quantity[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market5.current_price[ci] * amount
txt.print(" Total price: ")
util5.print_10s(price)
if price > ship5.cash {
txt.print(" Not enough cash!\n")
} else {
ship5.cash -= price
ship5.cargohold[ci] += amount
market5.current_quantity[ci] -= amount
}
}
}
}
sub do_sell() {
txt.print("\nSell what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market5.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if ship5.cargohold[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market5.current_price[ci] * amount
txt.print(" Total price: ")
util5.print_10s(price)
ship5.cash += price
ship5.cargohold[ci] -= amount
market5.current_quantity[ci] += amount
}
}
}
sub do_fuel() {
txt.print("\nBuy fuel. Amount? ")
void txt.input_chars(input)
ubyte buy_fuel = 10*conv.str2ubyte(input)
ubyte max_fuel = ship5.Max_fuel - ship5.fuel
if buy_fuel > max_fuel
buy_fuel = max_fuel
uword price = buy_fuel as uword * ship5.Fuel_cost
if price > ship5.cash {
txt.print("Not enough cash!\n")
} else {
ship5.cash -= price
ship5.fuel += buy_fuel
}
}
sub do_cash() {
txt.print("\nCheat! Set cash amount: ")
void txt.input_chars(input)
ship5.cash = conv.str2uword(input)
}
sub do_hold() {
txt.print("\nCheat! Set cargohold size: ")
void txt.input_chars(input)
ship5.Max_cargo = conv.str2ubyte(input)
}
sub do_next_galaxy5() {
galaxy5.travel_to(galaxy5.number+1, planet5.number)
planet5.display(false)
}
sub do_info() {
txt.print("\nSystem name (empty=current): ")
num_chars = txt.input_chars(input)
if num_chars {
ubyte current_planet5 = planet5.number
if galaxy5.search_closest_planet5(input) {
planet5.display(false)
} else {
txt.print(" Not found!")
}
galaxy5.travel_to(galaxy5.number, current_planet5)
} else {
planet5.display(false)
}
}
sub do_local() {
galaxy5.local_area()
}
sub do_show_market5() {
market5.display()
txt.print("\nFuel: ")
util5.print_10s(ship5.fuel)
txt.print(" Cargohold space: ")
txt.print_ub(ship5.cargo_free())
txt.print("t\n")
}
}
ship5 {
const ubyte Max_fuel = 70
const ubyte Fuel_cost = 2
ubyte Max_cargo = 20
ubyte fuel = Max_fuel
uword cash = 1000 ; actually has to be 4 bytes for the ultra rich....
ubyte[17] cargohold = 0
sub init() {
sys.memset(cargohold, len(cargohold), 0)
}
sub cargo_free() -> ubyte {
ubyte ci
ubyte total = 0
for ci in 0 to len(cargohold)-1 {
if market5.units[ci]==0 ; tonnes only
total += cargohold[ci]
}
return Max_cargo - total
}
}
market5 {
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
ubyte[17] units = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0]
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
ubyte[17] current_quantity = 0
uword[17] current_price = 0
sub init(ubyte fluct) {
; Prices and availabilities are influenced by the planet5's economy type
; (0-7) and a random "fluctuation" byte that was kept within the saved
; commander position to keep the market5 prices constant over gamesaves.
; Availabilities must be saved with the game since the player alters them
; by buying (and selling(?))
;
; Almost all operations are one byte only and overflow "errors" are
; extremely frequent and exploited.
;
; Trade Item prices are held internally in a single byte=true value/4.
; The decimal point in prices is introduced only when printing them.
; Internally, all prices are integers.
; The player's cash is held in four bytes.
ubyte ci
for ci in 0 to len(names)-1 {
word product
byte changing
product = planet5.economy as word * gradients[ci]
changing = fluct & maskbytes[ci] as byte
ubyte q = (basequants[ci] as word + changing - product) as ubyte
if q & $80
q = 0 ; clip to positive 8-bit
current_quantity[ci] = q & $3f
q = (baseprices[ci] + changing + product) as ubyte
current_price[ci] = q * $0004
}
current_quantity[16] = 0 ; force nonavailability of Alien Items
}
sub display() {
ubyte ci
txt.nl()
planet5.print_name_uppercase()
txt.print(" trade market5:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
for ci in 0 to len(names)-1 {
util5.print_right(13, names[ci])
txt.print(" ")
util5.print_10s(current_price[ci])
txt.print(" ")
txt.print_ub(current_quantity[ci])
when units[ci] {
0 -> txt.chrout('t')
1 -> txt.print("kg")
2 -> txt.chrout('g')
}
txt.print(" ")
txt.print_ub(ship5.cargohold[ci])
txt.nl()
}
}
sub match(uword nameptr) -> ubyte {
ubyte ci
for ci in 0 to len(names)-1 {
if util5.prefix_matches(nameptr, names[ci])
return ci
}
return 255
}
}
galaxy5 {
const uword GALSIZE = 256
const uword base0 = $5A4A ; seeds for the first galaxy5
const uword base1 = $0248
const uword base2 = $B753
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
ubyte number
uword[3] seed
sub init(ubyte galaxy5num) {
number = 1
planet5.number = 255
seed[0] = base0
seed[1] = base1
seed[2] = base2
repeat galaxy5num-1 {
nextgalaxy5()
}
}
sub nextgalaxy5() {
seed[0] = twist(seed[0])
seed[1] = twist(seed[1])
seed[2] = twist(seed[2])
number++
if number==9
number = 1
}
sub travel_to(ubyte galaxy5num, ubyte system) {
init(galaxy5num)
generate_next_planet5() ; always at least planet5 0 (separate to avoid repeat ubyte overflow)
repeat system {
generate_next_planet5()
}
planet5.name = make_current_planet5_name()
init_market5_for_planet5()
}
sub init_market5_for_planet5() {
market5.init(lsb(seed[0])+msb(seed[2]))
}
sub search_closest_planet5(uword nameptr) -> ubyte {
ubyte x = planet5.x
ubyte y = planet5.y
ubyte current_planet5_num = planet5.number
init(number)
ubyte found = false
ubyte current_closest_pi
ubyte current_distance = 127
ubyte pi
for pi in 0 to 255 {
generate_next_planet5()
planet5.name = make_current_planet5_name()
if util5.prefix_matches(nameptr, planet5.name) {
ubyte distance = planet5.distance(x, y)
if distance < current_distance {
current_distance = distance
current_closest_pi = pi
found = true
}
}
}
if found
travel_to(number, current_closest_pi)
else
travel_to(number, current_planet5_num)
return found
}
sub local_area() {
ubyte current_planet5 = planet5.number
ubyte px = planet5.x
ubyte py = planet5.y
ubyte pn = 0
init(number)
txt.print("\nGalaxy #")
txt.print_ub(number)
txt.print(" - systems in vicinity:\n")
do {
generate_next_planet5()
ubyte distance = planet5.distance(px, py)
if distance <= ship5.Max_fuel {
if distance <= ship5.fuel
txt.chrout('*')
else
txt.chrout('-')
txt.spc()
planet5.name = make_current_planet5_name()
planet5.display(true)
txt.print(" (")
util5.print_10s(distance)
txt.print(" LY)\n")
}
pn++
} until pn==0
travel_to(number, current_planet5)
}
ubyte pn_pair1
ubyte pn_pair2
ubyte pn_pair3
ubyte pn_pair4
ubyte longname
sub generate_next_planet5() {
determine_planet5_properties()
longname = lsb(seed[0]) & 64
; Always four iterations of random number
pn_pair1 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair2 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair3 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair4 = (msb(seed[2]) & 31) * 2
tweakseed()
}
sub make_current_planet5_name() -> str {
ubyte ni = 0
str name = " " ; max 8
if pn_pairs[pn_pair1] != '.' {
name[ni] = pn_pairs[pn_pair1]
ni++
}
if pn_pairs[pn_pair1+1] != '.' {
name[ni] = pn_pairs[pn_pair1+1]
ni++
}
if pn_pairs[pn_pair2] != '.' {
name[ni] = pn_pairs[pn_pair2]
ni++
}
if pn_pairs[pn_pair2+1] != '.' {
name[ni] = pn_pairs[pn_pair2+1]
ni++
}
if pn_pairs[pn_pair3] != '.' {
name[ni] = pn_pairs[pn_pair3]
ni++
}
if pn_pairs[pn_pair3+1] != '.' {
name[ni] = pn_pairs[pn_pair3+1]
ni++
}
if longname {
if pn_pairs[pn_pair4] != '.' {
name[ni] = pn_pairs[pn_pair4]
ni++
}
if pn_pairs[pn_pair4+1] != '.' {
name[ni] = pn_pairs[pn_pair4+1]
ni++
}
}
name[ni] = 0
return name
}
sub determine_planet5_properties() {
; create the planet5's characteristics
planet5.number++
planet5.x = msb(seed[1])
planet5.y = msb(seed[0])
planet5.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
planet5.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
if planet5.govtype <= 1
planet5.economy = (planet5.economy | 2)
planet5.techlevel = (msb(seed[1]) & 3) + (planet5.economy ^ 7)
planet5.techlevel += planet5.govtype >> 1
if planet5.govtype & 1
planet5.techlevel++
planet5.population = 4 * planet5.techlevel + planet5.economy
planet5.population += planet5.govtype + 1
planet5.productivity = ((planet5.economy ^ 7) + 3) * (planet5.govtype + 4)
planet5.productivity *= planet5.population * 8
ubyte seed2_msb = msb(seed[2])
planet5.radius = mkword((seed2_msb & 15) + 11, planet5.x)
planet5.species_is_alien = lsb(seed[2]) & 128 ; bit 7 of w2_lo
if planet5.species_is_alien {
planet5.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
planet5.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
planet5.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
planet5.species_kind = (planet5.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
}
planet5.goatsoup_seed[0] = lsb(seed[1])
planet5.goatsoup_seed[1] = msb(seed[1])
planet5.goatsoup_seed[2] = lsb(seed[2])
planet5.goatsoup_seed[3] = seed2_msb
}
sub tweakseed() {
uword temp = seed[0] + seed[1] + seed[2]
seed[0] = seed[1]
seed[1] = seed[2]
seed[2] = temp
}
sub twist(uword x) -> uword {
ubyte xh = msb(x)
ubyte xl = lsb(x)
rol(xh)
rol(xl)
return mkword(xh, xl)
}
sub debug_seed() {
txt.print("\ngalaxy5 #")
txt.print_ub(number)
txt.print("\ngalaxy5 seed0=")
txt.print_uwhex(galaxy5.seed[0], true)
txt.print("\ngalaxy5 seed1=")
txt.print_uwhex(galaxy5.seed[1], true)
txt.print("\ngalaxy5 seed2=")
txt.print_uwhex(galaxy5.seed[2], true)
txt.nl()
}
}
planet5 {
%option force_output
str[] species_sizes = ["Large", "Fierce", "Small"]
str[] species_colors = ["Green", "Red", "Yellow", "Blue", "Black", "Harmless"]
str[] species_looks = ["Slimy", "Bug-Eyed", "Horned", "Bony", "Fat", "Furry"]
str[] species_kinds = ["Rodents", "Frogs", "Lizards", "Lobsters", "Birds", "Humanoids", "Felines", "Insects"]
str[] govnames = ["Anarchy", "Feudal", "Multi-gov", "Dictatorship5", "Communist", "Confederacy", "Democracy", "Corporate State"]
str[] econnames = ["Rich Industrial", "Average Industrial", "Poor Industrial", "Mainly Industrial",
"Mainly Agricultural", "Rich Agricultural", "Average Agricultural", "Poor Agricultural"]
str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
str[] words82 = ["very", "mildly", "most", "reasonably", ""]
str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
str[] words8F = ["\xB0", "The planet5 \xB0", "The world \xB0", "This planet5", "This world"]
str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
str[] words91 = ["planet5", "world", "place", "little planet5", "dump"]
str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
uword[] wordlists = [
words81, words82, words83, words84, words85, words86, words87, words88,
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
words91, words92, words93, words94, words95, words96, words97, words98,
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
wordsA1, wordsA2, wordsA3, wordsA4]
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
str name = " " ; 8 max
ubyte number ; starts at 0 in new galaxy5, then increases by 1 for each generated planet5
ubyte x
ubyte y
ubyte economy
ubyte govtype
ubyte techlevel
ubyte population
uword productivity
uword radius
ubyte species_is_alien ; otherwise "Human Colonials"
ubyte species_size
ubyte species_color
ubyte species_look
ubyte species_kind
sub set_seed(uword s1, uword s2) {
goatsoup_seed[0] = lsb(s1)
goatsoup_seed[1] = msb(s1)
goatsoup_seed[2] = lsb(s2)
goatsoup_seed[3] = msb(s2)
reset_rnd()
}
sub reset_rnd() {
goatsoup_rnd[0] = goatsoup_seed[0]
goatsoup_rnd[1] = goatsoup_seed[1]
goatsoup_rnd[2] = goatsoup_seed[2]
goatsoup_rnd[3] = goatsoup_seed[3]
}
sub random_name() -> str {
ubyte ii
str name = " " ; 8 chars max
ubyte nx = 0
for ii in 0 to goatsoup_rnd_number() & 3 {
ubyte x = goatsoup_rnd_number() & $3e
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
x++
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
}
name[nx] = 0
name[0] |= 32 ; uppercase first letter
return name
}
sub goatsoup_rnd_number() -> ubyte {
ubyte x = goatsoup_rnd[0] * 2
uword a = x as uword + goatsoup_rnd[2]
if goatsoup_rnd[0] > 127
a ++
goatsoup_rnd[0] = lsb(a)
goatsoup_rnd[2] = x
x = goatsoup_rnd[1]
ubyte ac = x + goatsoup_rnd[3] + msb(a)
goatsoup_rnd[1] = ac
goatsoup_rnd[3] = x
return ac
}
sub distance(ubyte px, ubyte py) -> ubyte {
uword ax
uword ay
if px>x
ax=px-x
else
ax=x-px
if py>y
ay=py-y
else
ay=y-py
ay /= 2
ubyte d = sqrt16(ax*ax + ay*ay)
if d>63
return 255
return d*4
}
sub soup() -> str {
str planet5_result = " " * 160
uword[6] source_stack
ubyte stack_ptr = 0
str start_source = "\x8F is \x97."
uword source_ptr = &start_source
uword result_ptr = &planet5_result
reset_rnd()
recursive_soup()
return planet5_result
sub recursive_soup() {
repeat {
ubyte c = @(source_ptr)
source_ptr++
if c == $00 {
@(result_ptr) = 0
return
}
else if c <= $80 {
@(result_ptr) = c
result_ptr++
}
else {
if c <= $a4 {
ubyte rnr = goatsoup_rnd_number()
ubyte wordNr = (rnr >= $33) + (rnr >= $66) + (rnr >= $99) + (rnr >= $CC)
source_stack[stack_ptr] = source_ptr
stack_ptr++
source_ptr = getword(c, wordNr)
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
stack_ptr--
source_ptr = source_stack[stack_ptr]
} else {
if c == $b0 {
@(result_ptr) = name[0] | 32
result_ptr++
concat_string(&name + 1)
}
else if c == $b1 {
@(result_ptr) = name[0] | 32
result_ptr++
ubyte ni
for ni in 1 to len(name) {
ubyte cc = name[ni]
if cc=='e' or cc=='o' or cc==0
break
else {
@(result_ptr) = cc
result_ptr++
}
}
@(result_ptr) = 'i'
result_ptr++
@(result_ptr) = 'a'
result_ptr++
@(result_ptr) = 'n'
result_ptr++
}
else if c == $b2 {
concat_string(random_name())
}
else {
@(result_ptr) = c
result_ptr++
}
}
}
}
}
sub concat_string(uword str_ptr) {
repeat {
ubyte c = @(str_ptr)
if c==0
break
else {
@(result_ptr) = c
str_ptr++
result_ptr++
}
}
}
}
sub display(ubyte compressed) {
if compressed {
print_name_uppercase()
txt.print(" TL:")
txt.print_ub(techlevel+1)
txt.spc()
txt.print(econnames[economy])
txt.spc()
txt.print(govnames[govtype])
} else {
txt.print("\n\nSystem: ")
print_name_uppercase()
txt.print("\nPosition: ")
txt.print_ub(x)
txt.chrout('\'')
txt.print_ub(y)
txt.spc()
txt.chrout('#')
txt.print_ub(number)
txt.print("\nEconomy: ")
txt.print(econnames[economy])
txt.print("\nGovernment: ")
txt.print(govnames[govtype])
txt.print("\nTech Level: ")
txt.print_ub(techlevel+1)
txt.print("\nTurnover: ")
txt.print_uw(productivity)
txt.print("\nRadius: ")
txt.print_uw(radius)
txt.print("\nPopulation: ")
txt.print_ub(population >> 3)
txt.print(" Billion\nSpecies: ")
if species_is_alien {
if species_size < len(species_sizes) {
txt.print(species_sizes[species_size])
txt.spc()
}
if species_color < len(species_colors) {
txt.print(species_colors[species_color])
txt.spc()
}
if species_look < len(species_looks) {
txt.print(species_looks[species_look])
txt.spc()
}
if species_kind < len(species_kinds) {
txt.print(species_kinds[species_kind])
}
} else {
txt.print("Human Colonials")
}
txt.nl()
txt.print(soup())
txt.nl()
}
}
sub print_name_uppercase() {
ubyte c
for c in name
txt.chrout(c | 32)
}
asmsub getword(ubyte list @A, ubyte wordidx @Y) -> uword @AY {
%asm {{
sty P8ZP_SCRATCH_REG
sec
sbc #$81
asl a
tay
lda wordlists,y
sta P8ZP_SCRATCH_W1
lda wordlists+1,y
sta P8ZP_SCRATCH_W1+1
lda P8ZP_SCRATCH_REG
asl a
tay
lda (P8ZP_SCRATCH_W1),y
pha
iny
lda (P8ZP_SCRATCH_W1),y
tay
pla
rts
}}
}
}
util5 {
sub prefix_matches(uword prefixptr, uword stringptr) -> ubyte {
repeat {
ubyte pc = @(prefixptr)
ubyte sc = @(stringptr)
if pc == 0
return true
; to lowercase for case insensitive compare:
pc &= 127
sc &= 127
if pc != sc
return false
prefixptr++
stringptr++
}
return false
}
sub print_right(ubyte width, uword st) {
repeat width - string.length(st) {
txt.spc()
}
txt.print(st)
}
asmsub print_10s(uword value @AY) clobbers(A, X, Y) {
%asm {{
jsr conv.uword2decimal
lda conv.uword2decimal.decTenThousands
ldy #0 ; have we started printing?
cmp #'0'
beq +
jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decThousands
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decHundreds
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decTens
jsr c64.CHROUT
lda #'.'
jsr c64.CHROUT
lda conv.uword2decimal.decOnes
jsr c64.CHROUT
rts
}}
}
}

View File

@ -1,994 +0,0 @@
%import textio
%import conv
%import diskio
%import string
%import test_stack
%option no_sysinit
%zeropage basicsafe
; Prog8 adaptation of the Text-Elite galaxy6 system trading simulation engine.
; Original C-version obtained from: http://www.elitehomepage.org/text/index.htm
; Note: this program is compatible with C64 and CX16.
perf6 {
const ubyte numforLave = 7 ; Lave is 7th generated planet6 in galaxy6 one
const ubyte numforZaonce = 129
const ubyte numforDiso = 147
const ubyte numforRiedquat = 46
sub start() {
txt.lowercase()
txt.print("\u000c\n --- TextElite v1.1 ---\n")
galaxy6.travel_to(1, numforLave)
market6.init(0) ; Lave's market6 is seeded with 0
ship6.init()
planet6.display(false)
repeat {
; test_stack.test()
str input = "????????"
txt.print("\nCash: ")
util6.print_10s(ship6.cash)
txt.print("\nCommand (?=help): ")
ubyte num_chars = txt.input_chars(input)
txt.nl()
if num_chars {
when input[0] {
'?' -> {
txt.print("\nCommands are:\n"+
"buy jump info cash >=save\n"+
"sell teleport market6 hold <=load\n"+
"fuel galhyp local quit\n")
}
'q' -> break
'b' -> trader6.do_buy()
's' -> trader6.do_sell()
'f' -> trader6.do_fuel()
'j' -> trader6.do_jump()
't' -> trader6.do_teleport()
'g' -> trader6.do_next_galaxy6()
'i' -> trader6.do_info()
'm' -> trader6.do_show_market6()
'l' -> trader6.do_local()
'c' -> trader6.do_cash()
'h' -> trader6.do_hold()
'<' -> trader6.do_load()
'>' -> trader6.do_save()
}
}
}
}
}
trader6 {
str Savegame = "↑commander.save"
str input = "??????????"
ubyte num_chars
struct SaveData {
ubyte galaxy6
ubyte planet6
ubyte cargo0
ubyte cargo1
ubyte cargo2
ubyte cargo3
ubyte cargo4
ubyte cargo5
ubyte cargo6
ubyte cargo7
ubyte cargo8
ubyte cargo9
ubyte cargo10
ubyte cargo11
ubyte cargo12
ubyte cargo13
ubyte cargo14
ubyte cargo15
ubyte cargo16
uword cash
ubyte max_cargo
ubyte fuel
}
SaveData savedata
sub do_load() {
txt.print("\nLoading universe...")
if diskio.load(8, Savegame, &savedata) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
return
}
ship6.cash = savedata.cash
ship6.Max_cargo = savedata.max_cargo
ship6.fuel = savedata.fuel
sys.memcopy(&savedata.cargo0, ship6.cargohold, len(ship6.cargohold))
galaxy6.travel_to(savedata.galaxy6, savedata.planet6)
planet6.display(false)
}
sub do_save() {
savedata.galaxy6 = galaxy6.number
savedata.planet6 = planet6.number
savedata.cash = ship6.cash
savedata.max_cargo = ship6.Max_cargo
savedata.fuel = ship6.fuel
sys.memcopy(ship6.cargohold, &savedata.cargo0, len(ship6.cargohold))
txt.print("\nSaving universe...")
diskio.delete(8, Savegame)
if diskio.save(8, Savegame, &savedata, sizeof(savedata)) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
}
}
sub do_jump() {
txt.print("\nJump to what system? ")
jump_to_system()
}
sub do_teleport() {
txt.print("\nCheat! Teleport to what system? ")
ubyte fuel = ship6.fuel
ship6.fuel = 255
jump_to_system()
ship6.fuel = fuel
}
sub jump_to_system() {
void txt.input_chars(input)
ubyte current_planet6 = planet6.number
ubyte x = planet6.x
ubyte y = planet6.y
if galaxy6.search_closest_planet6(input) {
ubyte distance = planet6.distance(x, y)
if distance <= ship6.fuel {
galaxy6.init_market6_for_planet6()
ship6.fuel -= distance
txt.print("\n\nHyperspace jump! Arrived at:\n")
planet6.display(true)
return
}
txt.print("Insufficient fuel\n")
} else {
txt.print(" Not found!\n")
}
galaxy6.travel_to(galaxy6.number, current_planet6)
}
sub do_buy() {
txt.print("\nBuy what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market6.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if market6.current_quantity[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market6.current_price[ci] * amount
txt.print(" Total price: ")
util6.print_10s(price)
if price > ship6.cash {
txt.print(" Not enough cash!\n")
} else {
ship6.cash -= price
ship6.cargohold[ci] += amount
market6.current_quantity[ci] -= amount
}
}
}
}
sub do_sell() {
txt.print("\nSell what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market6.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if ship6.cargohold[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market6.current_price[ci] * amount
txt.print(" Total price: ")
util6.print_10s(price)
ship6.cash += price
ship6.cargohold[ci] -= amount
market6.current_quantity[ci] += amount
}
}
}
sub do_fuel() {
txt.print("\nBuy fuel. Amount? ")
void txt.input_chars(input)
ubyte buy_fuel = 10*conv.str2ubyte(input)
ubyte max_fuel = ship6.Max_fuel - ship6.fuel
if buy_fuel > max_fuel
buy_fuel = max_fuel
uword price = buy_fuel as uword * ship6.Fuel_cost
if price > ship6.cash {
txt.print("Not enough cash!\n")
} else {
ship6.cash -= price
ship6.fuel += buy_fuel
}
}
sub do_cash() {
txt.print("\nCheat! Set cash amount: ")
void txt.input_chars(input)
ship6.cash = conv.str2uword(input)
}
sub do_hold() {
txt.print("\nCheat! Set cargohold size: ")
void txt.input_chars(input)
ship6.Max_cargo = conv.str2ubyte(input)
}
sub do_next_galaxy6() {
galaxy6.travel_to(galaxy6.number+1, planet6.number)
planet6.display(false)
}
sub do_info() {
txt.print("\nSystem name (empty=current): ")
num_chars = txt.input_chars(input)
if num_chars {
ubyte current_planet6 = planet6.number
if galaxy6.search_closest_planet6(input) {
planet6.display(false)
} else {
txt.print(" Not found!")
}
galaxy6.travel_to(galaxy6.number, current_planet6)
} else {
planet6.display(false)
}
}
sub do_local() {
galaxy6.local_area()
}
sub do_show_market6() {
market6.display()
txt.print("\nFuel: ")
util6.print_10s(ship6.fuel)
txt.print(" Cargohold space: ")
txt.print_ub(ship6.cargo_free())
txt.print("t\n")
}
}
ship6 {
const ubyte Max_fuel = 70
const ubyte Fuel_cost = 2
ubyte Max_cargo = 20
ubyte fuel = Max_fuel
uword cash = 1000 ; actually has to be 4 bytes for the ultra rich....
ubyte[17] cargohold = 0
sub init() {
sys.memset(cargohold, len(cargohold), 0)
}
sub cargo_free() -> ubyte {
ubyte ci
ubyte total = 0
for ci in 0 to len(cargohold)-1 {
if market6.units[ci]==0 ; tonnes only
total += cargohold[ci]
}
return Max_cargo - total
}
}
market6 {
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
ubyte[17] units = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0]
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
ubyte[17] current_quantity = 0
uword[17] current_price = 0
sub init(ubyte fluct) {
; Prices and availabilities are influenced by the planet6's economy type
; (0-7) and a random "fluctuation" byte that was kept within the saved
; commander position to keep the market6 prices constant over gamesaves.
; Availabilities must be saved with the game since the player alters them
; by buying (and selling(?))
;
; Almost all operations are one byte only and overflow "errors" are
; extremely frequent and exploited.
;
; Trade Item prices are held internally in a single byte=true value/4.
; The decimal point in prices is introduced only when printing them.
; Internally, all prices are integers.
; The player's cash is held in four bytes.
ubyte ci
for ci in 0 to len(names)-1 {
word product
byte changing
product = planet6.economy as word * gradients[ci]
changing = fluct & maskbytes[ci] as byte
ubyte q = (basequants[ci] as word + changing - product) as ubyte
if q & $80
q = 0 ; clip to positive 8-bit
current_quantity[ci] = q & $3f
q = (baseprices[ci] + changing + product) as ubyte
current_price[ci] = q * $0004
}
current_quantity[16] = 0 ; force nonavailability of Alien Items
}
sub display() {
ubyte ci
txt.nl()
planet6.print_name_uppercase()
txt.print(" trade market6:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
for ci in 0 to len(names)-1 {
util6.print_right(13, names[ci])
txt.print(" ")
util6.print_10s(current_price[ci])
txt.print(" ")
txt.print_ub(current_quantity[ci])
when units[ci] {
0 -> txt.chrout('t')
1 -> txt.print("kg")
2 -> txt.chrout('g')
}
txt.print(" ")
txt.print_ub(ship6.cargohold[ci])
txt.nl()
}
}
sub match(uword nameptr) -> ubyte {
ubyte ci
for ci in 0 to len(names)-1 {
if util6.prefix_matches(nameptr, names[ci])
return ci
}
return 255
}
}
galaxy6 {
const uword GALSIZE = 256
const uword base0 = $5A4A ; seeds for the first galaxy6
const uword base1 = $0248
const uword base2 = $B753
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
ubyte number
uword[3] seed
sub init(ubyte galaxy6num) {
number = 1
planet6.number = 255
seed[0] = base0
seed[1] = base1
seed[2] = base2
repeat galaxy6num-1 {
nextgalaxy6()
}
}
sub nextgalaxy6() {
seed[0] = twist(seed[0])
seed[1] = twist(seed[1])
seed[2] = twist(seed[2])
number++
if number==9
number = 1
}
sub travel_to(ubyte galaxy6num, ubyte system) {
init(galaxy6num)
generate_next_planet6() ; always at least planet6 0 (separate to avoid repeat ubyte overflow)
repeat system {
generate_next_planet6()
}
planet6.name = make_current_planet6_name()
init_market6_for_planet6()
}
sub init_market6_for_planet6() {
market6.init(lsb(seed[0])+msb(seed[2]))
}
sub search_closest_planet6(uword nameptr) -> ubyte {
ubyte x = planet6.x
ubyte y = planet6.y
ubyte current_planet6_num = planet6.number
init(number)
ubyte found = false
ubyte current_closest_pi
ubyte current_distance = 127
ubyte pi
for pi in 0 to 255 {
generate_next_planet6()
planet6.name = make_current_planet6_name()
if util6.prefix_matches(nameptr, planet6.name) {
ubyte distance = planet6.distance(x, y)
if distance < current_distance {
current_distance = distance
current_closest_pi = pi
found = true
}
}
}
if found
travel_to(number, current_closest_pi)
else
travel_to(number, current_planet6_num)
return found
}
sub local_area() {
ubyte current_planet6 = planet6.number
ubyte px = planet6.x
ubyte py = planet6.y
ubyte pn = 0
init(number)
txt.print("\nGalaxy #")
txt.print_ub(number)
txt.print(" - systems in vicinity:\n")
do {
generate_next_planet6()
ubyte distance = planet6.distance(px, py)
if distance <= ship6.Max_fuel {
if distance <= ship6.fuel
txt.chrout('*')
else
txt.chrout('-')
txt.spc()
planet6.name = make_current_planet6_name()
planet6.display(true)
txt.print(" (")
util6.print_10s(distance)
txt.print(" LY)\n")
}
pn++
} until pn==0
travel_to(number, current_planet6)
}
ubyte pn_pair1
ubyte pn_pair2
ubyte pn_pair3
ubyte pn_pair4
ubyte longname
sub generate_next_planet6() {
determine_planet6_properties()
longname = lsb(seed[0]) & 64
; Always four iterations of random number
pn_pair1 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair2 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair3 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair4 = (msb(seed[2]) & 31) * 2
tweakseed()
}
sub make_current_planet6_name() -> str {
ubyte ni = 0
str name = " " ; max 8
if pn_pairs[pn_pair1] != '.' {
name[ni] = pn_pairs[pn_pair1]
ni++
}
if pn_pairs[pn_pair1+1] != '.' {
name[ni] = pn_pairs[pn_pair1+1]
ni++
}
if pn_pairs[pn_pair2] != '.' {
name[ni] = pn_pairs[pn_pair2]
ni++
}
if pn_pairs[pn_pair2+1] != '.' {
name[ni] = pn_pairs[pn_pair2+1]
ni++
}
if pn_pairs[pn_pair3] != '.' {
name[ni] = pn_pairs[pn_pair3]
ni++
}
if pn_pairs[pn_pair3+1] != '.' {
name[ni] = pn_pairs[pn_pair3+1]
ni++
}
if longname {
if pn_pairs[pn_pair4] != '.' {
name[ni] = pn_pairs[pn_pair4]
ni++
}
if pn_pairs[pn_pair4+1] != '.' {
name[ni] = pn_pairs[pn_pair4+1]
ni++
}
}
name[ni] = 0
return name
}
sub determine_planet6_properties() {
; create the planet6's characteristics
planet6.number++
planet6.x = msb(seed[1])
planet6.y = msb(seed[0])
planet6.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
planet6.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
if planet6.govtype <= 1
planet6.economy = (planet6.economy | 2)
planet6.techlevel = (msb(seed[1]) & 3) + (planet6.economy ^ 7)
planet6.techlevel += planet6.govtype >> 1
if planet6.govtype & 1
planet6.techlevel++
planet6.population = 4 * planet6.techlevel + planet6.economy
planet6.population += planet6.govtype + 1
planet6.productivity = ((planet6.economy ^ 7) + 3) * (planet6.govtype + 4)
planet6.productivity *= planet6.population * 8
ubyte seed2_msb = msb(seed[2])
planet6.radius = mkword((seed2_msb & 15) + 11, planet6.x)
planet6.species_is_alien = lsb(seed[2]) & 128 ; bit 7 of w2_lo
if planet6.species_is_alien {
planet6.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
planet6.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
planet6.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
planet6.species_kind = (planet6.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
}
planet6.goatsoup_seed[0] = lsb(seed[1])
planet6.goatsoup_seed[1] = msb(seed[1])
planet6.goatsoup_seed[2] = lsb(seed[2])
planet6.goatsoup_seed[3] = seed2_msb
}
sub tweakseed() {
uword temp = seed[0] + seed[1] + seed[2]
seed[0] = seed[1]
seed[1] = seed[2]
seed[2] = temp
}
sub twist(uword x) -> uword {
ubyte xh = msb(x)
ubyte xl = lsb(x)
rol(xh)
rol(xl)
return mkword(xh, xl)
}
sub debug_seed() {
txt.print("\ngalaxy6 #")
txt.print_ub(number)
txt.print("\ngalaxy6 seed0=")
txt.print_uwhex(galaxy6.seed[0], true)
txt.print("\ngalaxy6 seed1=")
txt.print_uwhex(galaxy6.seed[1], true)
txt.print("\ngalaxy6 seed2=")
txt.print_uwhex(galaxy6.seed[2], true)
txt.nl()
}
}
planet6 {
%option force_output
str[] species_sizes = ["Large", "Fierce", "Small"]
str[] species_colors = ["Green", "Red", "Yellow", "Blue", "Black", "Harmless"]
str[] species_looks = ["Slimy", "Bug-Eyed", "Horned", "Bony", "Fat", "Furry"]
str[] species_kinds = ["Rodents", "Frogs", "Lizards", "Lobsters", "Birds", "Humanoids", "Felines", "Insects"]
str[] govnames = ["Anarchy", "Feudal", "Multi-gov", "Dictatorship6", "Communist", "Confederacy", "Democracy", "Corporate State"]
str[] econnames = ["Rich Industrial", "Average Industrial", "Poor Industrial", "Mainly Industrial",
"Mainly Agricultural", "Rich Agricultural", "Average Agricultural", "Poor Agricultural"]
str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
str[] words82 = ["very", "mildly", "most", "reasonably", ""]
str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
str[] words8F = ["\xB0", "The planet6 \xB0", "The world \xB0", "This planet6", "This world"]
str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
str[] words91 = ["planet6", "world", "place", "little planet6", "dump"]
str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
uword[] wordlists = [
words81, words82, words83, words84, words85, words86, words87, words88,
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
words91, words92, words93, words94, words95, words96, words97, words98,
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
wordsA1, wordsA2, wordsA3, wordsA4]
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
str name = " " ; 8 max
ubyte number ; starts at 0 in new galaxy6, then increases by 1 for each generated planet6
ubyte x
ubyte y
ubyte economy
ubyte govtype
ubyte techlevel
ubyte population
uword productivity
uword radius
ubyte species_is_alien ; otherwise "Human Colonials"
ubyte species_size
ubyte species_color
ubyte species_look
ubyte species_kind
sub set_seed(uword s1, uword s2) {
goatsoup_seed[0] = lsb(s1)
goatsoup_seed[1] = msb(s1)
goatsoup_seed[2] = lsb(s2)
goatsoup_seed[3] = msb(s2)
reset_rnd()
}
sub reset_rnd() {
goatsoup_rnd[0] = goatsoup_seed[0]
goatsoup_rnd[1] = goatsoup_seed[1]
goatsoup_rnd[2] = goatsoup_seed[2]
goatsoup_rnd[3] = goatsoup_seed[3]
}
sub random_name() -> str {
ubyte ii
str name = " " ; 8 chars max
ubyte nx = 0
for ii in 0 to goatsoup_rnd_number() & 3 {
ubyte x = goatsoup_rnd_number() & $3e
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
x++
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
}
name[nx] = 0
name[0] |= 32 ; uppercase first letter
return name
}
sub goatsoup_rnd_number() -> ubyte {
ubyte x = goatsoup_rnd[0] * 2
uword a = x as uword + goatsoup_rnd[2]
if goatsoup_rnd[0] > 127
a ++
goatsoup_rnd[0] = lsb(a)
goatsoup_rnd[2] = x
x = goatsoup_rnd[1]
ubyte ac = x + goatsoup_rnd[3] + msb(a)
goatsoup_rnd[1] = ac
goatsoup_rnd[3] = x
return ac
}
sub distance(ubyte px, ubyte py) -> ubyte {
uword ax
uword ay
if px>x
ax=px-x
else
ax=x-px
if py>y
ay=py-y
else
ay=y-py
ay /= 2
ubyte d = sqrt16(ax*ax + ay*ay)
if d>63
return 255
return d*4
}
sub soup() -> str {
str planet6_result = " " * 160
uword[6] source_stack
ubyte stack_ptr = 0
str start_source = "\x8F is \x97."
uword source_ptr = &start_source
uword result_ptr = &planet6_result
reset_rnd()
recursive_soup()
return planet6_result
sub recursive_soup() {
repeat {
ubyte c = @(source_ptr)
source_ptr++
if c == $00 {
@(result_ptr) = 0
return
}
else if c <= $80 {
@(result_ptr) = c
result_ptr++
}
else {
if c <= $a4 {
ubyte rnr = goatsoup_rnd_number()
ubyte wordNr = (rnr >= $33) + (rnr >= $66) + (rnr >= $99) + (rnr >= $CC)
source_stack[stack_ptr] = source_ptr
stack_ptr++
source_ptr = getword(c, wordNr)
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
stack_ptr--
source_ptr = source_stack[stack_ptr]
} else {
if c == $b0 {
@(result_ptr) = name[0] | 32
result_ptr++
concat_string(&name + 1)
}
else if c == $b1 {
@(result_ptr) = name[0] | 32
result_ptr++
ubyte ni
for ni in 1 to len(name) {
ubyte cc = name[ni]
if cc=='e' or cc=='o' or cc==0
break
else {
@(result_ptr) = cc
result_ptr++
}
}
@(result_ptr) = 'i'
result_ptr++
@(result_ptr) = 'a'
result_ptr++
@(result_ptr) = 'n'
result_ptr++
}
else if c == $b2 {
concat_string(random_name())
}
else {
@(result_ptr) = c
result_ptr++
}
}
}
}
}
sub concat_string(uword str_ptr) {
repeat {
ubyte c = @(str_ptr)
if c==0
break
else {
@(result_ptr) = c
str_ptr++
result_ptr++
}
}
}
}
sub display(ubyte compressed) {
if compressed {
print_name_uppercase()
txt.print(" TL:")
txt.print_ub(techlevel+1)
txt.spc()
txt.print(econnames[economy])
txt.spc()
txt.print(govnames[govtype])
} else {
txt.print("\n\nSystem: ")
print_name_uppercase()
txt.print("\nPosition: ")
txt.print_ub(x)
txt.chrout('\'')
txt.print_ub(y)
txt.spc()
txt.chrout('#')
txt.print_ub(number)
txt.print("\nEconomy: ")
txt.print(econnames[economy])
txt.print("\nGovernment: ")
txt.print(govnames[govtype])
txt.print("\nTech Level: ")
txt.print_ub(techlevel+1)
txt.print("\nTurnover: ")
txt.print_uw(productivity)
txt.print("\nRadius: ")
txt.print_uw(radius)
txt.print("\nPopulation: ")
txt.print_ub(population >> 3)
txt.print(" Billion\nSpecies: ")
if species_is_alien {
if species_size < len(species_sizes) {
txt.print(species_sizes[species_size])
txt.spc()
}
if species_color < len(species_colors) {
txt.print(species_colors[species_color])
txt.spc()
}
if species_look < len(species_looks) {
txt.print(species_looks[species_look])
txt.spc()
}
if species_kind < len(species_kinds) {
txt.print(species_kinds[species_kind])
}
} else {
txt.print("Human Colonials")
}
txt.nl()
txt.print(soup())
txt.nl()
}
}
sub print_name_uppercase() {
ubyte c
for c in name
txt.chrout(c | 32)
}
asmsub getword(ubyte list @A, ubyte wordidx @Y) -> uword @AY {
%asm {{
sty P8ZP_SCRATCH_REG
sec
sbc #$81
asl a
tay
lda wordlists,y
sta P8ZP_SCRATCH_W1
lda wordlists+1,y
sta P8ZP_SCRATCH_W1+1
lda P8ZP_SCRATCH_REG
asl a
tay
lda (P8ZP_SCRATCH_W1),y
pha
iny
lda (P8ZP_SCRATCH_W1),y
tay
pla
rts
}}
}
}
util6 {
sub prefix_matches(uword prefixptr, uword stringptr) -> ubyte {
repeat {
ubyte pc = @(prefixptr)
ubyte sc = @(stringptr)
if pc == 0
return true
; to lowercase for case insensitive compare:
pc &= 127
sc &= 127
if pc != sc
return false
prefixptr++
stringptr++
}
return false
}
sub print_right(ubyte width, uword st) {
repeat width - string.length(st) {
txt.spc()
}
txt.print(st)
}
asmsub print_10s(uword value @AY) clobbers(A, X, Y) {
%asm {{
jsr conv.uword2decimal
lda conv.uword2decimal.decTenThousands
ldy #0 ; have we started printing?
cmp #'0'
beq +
jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decThousands
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decHundreds
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decTens
jsr c64.CHROUT
lda #'.'
jsr c64.CHROUT
lda conv.uword2decimal.decOnes
jsr c64.CHROUT
rts
}}
}
}

View File

@ -1,994 +0,0 @@
%import textio
%import conv
%import diskio
%import string
%import test_stack
%option no_sysinit
%zeropage basicsafe
; Prog8 adaptation of the Text-Elite galaxy7 system trading simulation engine.
; Original C-version obtained from: http://www.elitehomepage.org/text/index.htm
; Note: this program is compatible with C64 and CX16.
perf7 {
const ubyte numforLave = 7 ; Lave is 7th generated planet7 in galaxy7 one
const ubyte numforZaonce = 129
const ubyte numforDiso = 147
const ubyte numforRiedquat = 46
sub start() {
txt.lowercase()
txt.print("\u000c\n --- TextElite v1.1 ---\n")
galaxy7.travel_to(1, numforLave)
market7.init(0) ; Lave's market7 is seeded with 0
ship7.init()
planet7.display(false)
repeat {
; test_stack.test()
str input = "????????"
txt.print("\nCash: ")
util7.print_10s(ship7.cash)
txt.print("\nCommand (?=help): ")
ubyte num_chars = txt.input_chars(input)
txt.nl()
if num_chars {
when input[0] {
'?' -> {
txt.print("\nCommands are:\n"+
"buy jump info cash >=save\n"+
"sell teleport market7 hold <=load\n"+
"fuel galhyp local quit\n")
}
'q' -> break
'b' -> trader7.do_buy()
's' -> trader7.do_sell()
'f' -> trader7.do_fuel()
'j' -> trader7.do_jump()
't' -> trader7.do_teleport()
'g' -> trader7.do_next_galaxy7()
'i' -> trader7.do_info()
'm' -> trader7.do_show_market7()
'l' -> trader7.do_local()
'c' -> trader7.do_cash()
'h' -> trader7.do_hold()
'<' -> trader7.do_load()
'>' -> trader7.do_save()
}
}
}
}
}
trader7 {
str Savegame = "↑commander.save"
str input = "??????????"
ubyte num_chars
struct SaveData {
ubyte galaxy7
ubyte planet7
ubyte cargo0
ubyte cargo1
ubyte cargo2
ubyte cargo3
ubyte cargo4
ubyte cargo5
ubyte cargo6
ubyte cargo7
ubyte cargo8
ubyte cargo9
ubyte cargo10
ubyte cargo11
ubyte cargo12
ubyte cargo13
ubyte cargo14
ubyte cargo15
ubyte cargo16
uword cash
ubyte max_cargo
ubyte fuel
}
SaveData savedata
sub do_load() {
txt.print("\nLoading universe...")
if diskio.load(8, Savegame, &savedata) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
return
}
ship7.cash = savedata.cash
ship7.Max_cargo = savedata.max_cargo
ship7.fuel = savedata.fuel
sys.memcopy(&savedata.cargo0, ship7.cargohold, len(ship7.cargohold))
galaxy7.travel_to(savedata.galaxy7, savedata.planet7)
planet7.display(false)
}
sub do_save() {
savedata.galaxy7 = galaxy7.number
savedata.planet7 = planet7.number
savedata.cash = ship7.cash
savedata.max_cargo = ship7.Max_cargo
savedata.fuel = ship7.fuel
sys.memcopy(ship7.cargohold, &savedata.cargo0, len(ship7.cargohold))
txt.print("\nSaving universe...")
diskio.delete(8, Savegame)
if diskio.save(8, Savegame, &savedata, sizeof(savedata)) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
}
}
sub do_jump() {
txt.print("\nJump to what system? ")
jump_to_system()
}
sub do_teleport() {
txt.print("\nCheat! Teleport to what system? ")
ubyte fuel = ship7.fuel
ship7.fuel = 255
jump_to_system()
ship7.fuel = fuel
}
sub jump_to_system() {
void txt.input_chars(input)
ubyte current_planet7 = planet7.number
ubyte x = planet7.x
ubyte y = planet7.y
if galaxy7.search_closest_planet7(input) {
ubyte distance = planet7.distance(x, y)
if distance <= ship7.fuel {
galaxy7.init_market7_for_planet7()
ship7.fuel -= distance
txt.print("\n\nHyperspace jump! Arrived at:\n")
planet7.display(true)
return
}
txt.print("Insufficient fuel\n")
} else {
txt.print(" Not found!\n")
}
galaxy7.travel_to(galaxy7.number, current_planet7)
}
sub do_buy() {
txt.print("\nBuy what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market7.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if market7.current_quantity[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market7.current_price[ci] * amount
txt.print(" Total price: ")
util7.print_10s(price)
if price > ship7.cash {
txt.print(" Not enough cash!\n")
} else {
ship7.cash -= price
ship7.cargohold[ci] += amount
market7.current_quantity[ci] -= amount
}
}
}
}
sub do_sell() {
txt.print("\nSell what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market7.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if ship7.cargohold[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market7.current_price[ci] * amount
txt.print(" Total price: ")
util7.print_10s(price)
ship7.cash += price
ship7.cargohold[ci] -= amount
market7.current_quantity[ci] += amount
}
}
}
sub do_fuel() {
txt.print("\nBuy fuel. Amount? ")
void txt.input_chars(input)
ubyte buy_fuel = 10*conv.str2ubyte(input)
ubyte max_fuel = ship7.Max_fuel - ship7.fuel
if buy_fuel > max_fuel
buy_fuel = max_fuel
uword price = buy_fuel as uword * ship7.Fuel_cost
if price > ship7.cash {
txt.print("Not enough cash!\n")
} else {
ship7.cash -= price
ship7.fuel += buy_fuel
}
}
sub do_cash() {
txt.print("\nCheat! Set cash amount: ")
void txt.input_chars(input)
ship7.cash = conv.str2uword(input)
}
sub do_hold() {
txt.print("\nCheat! Set cargohold size: ")
void txt.input_chars(input)
ship7.Max_cargo = conv.str2ubyte(input)
}
sub do_next_galaxy7() {
galaxy7.travel_to(galaxy7.number+1, planet7.number)
planet7.display(false)
}
sub do_info() {
txt.print("\nSystem name (empty=current): ")
num_chars = txt.input_chars(input)
if num_chars {
ubyte current_planet7 = planet7.number
if galaxy7.search_closest_planet7(input) {
planet7.display(false)
} else {
txt.print(" Not found!")
}
galaxy7.travel_to(galaxy7.number, current_planet7)
} else {
planet7.display(false)
}
}
sub do_local() {
galaxy7.local_area()
}
sub do_show_market7() {
market7.display()
txt.print("\nFuel: ")
util7.print_10s(ship7.fuel)
txt.print(" Cargohold space: ")
txt.print_ub(ship7.cargo_free())
txt.print("t\n")
}
}
ship7 {
const ubyte Max_fuel = 70
const ubyte Fuel_cost = 2
ubyte Max_cargo = 20
ubyte fuel = Max_fuel
uword cash = 1000 ; actually has to be 4 bytes for the ultra rich....
ubyte[17] cargohold = 0
sub init() {
sys.memset(cargohold, len(cargohold), 0)
}
sub cargo_free() -> ubyte {
ubyte ci
ubyte total = 0
for ci in 0 to len(cargohold)-1 {
if market7.units[ci]==0 ; tonnes only
total += cargohold[ci]
}
return Max_cargo - total
}
}
market7 {
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
ubyte[17] units = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0]
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
ubyte[17] current_quantity = 0
uword[17] current_price = 0
sub init(ubyte fluct) {
; Prices and availabilities are influenced by the planet7's economy type
; (0-7) and a random "fluctuation" byte that was kept within the saved
; commander position to keep the market7 prices constant over gamesaves.
; Availabilities must be saved with the game since the player alters them
; by buying (and selling(?))
;
; Almost all operations are one byte only and overflow "errors" are
; extremely frequent and exploited.
;
; Trade Item prices are held internally in a single byte=true value/4.
; The decimal point in prices is introduced only when printing them.
; Internally, all prices are integers.
; The player's cash is held in four bytes.
ubyte ci
for ci in 0 to len(names)-1 {
word product
byte changing
product = planet7.economy as word * gradients[ci]
changing = fluct & maskbytes[ci] as byte
ubyte q = (basequants[ci] as word + changing - product) as ubyte
if q & $80
q = 0 ; clip to positive 8-bit
current_quantity[ci] = q & $3f
q = (baseprices[ci] + changing + product) as ubyte
current_price[ci] = q * $0004
}
current_quantity[16] = 0 ; force nonavailability of Alien Items
}
sub display() {
ubyte ci
txt.nl()
planet7.print_name_uppercase()
txt.print(" trade market7:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
for ci in 0 to len(names)-1 {
util7.print_right(13, names[ci])
txt.print(" ")
util7.print_10s(current_price[ci])
txt.print(" ")
txt.print_ub(current_quantity[ci])
when units[ci] {
0 -> txt.chrout('t')
1 -> txt.print("kg")
2 -> txt.chrout('g')
}
txt.print(" ")
txt.print_ub(ship7.cargohold[ci])
txt.nl()
}
}
sub match(uword nameptr) -> ubyte {
ubyte ci
for ci in 0 to len(names)-1 {
if util7.prefix_matches(nameptr, names[ci])
return ci
}
return 255
}
}
galaxy7 {
const uword GALSIZE = 256
const uword base0 = $5A4A ; seeds for the first galaxy7
const uword base1 = $0248
const uword base2 = $B753
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
ubyte number
uword[3] seed
sub init(ubyte galaxy7num) {
number = 1
planet7.number = 255
seed[0] = base0
seed[1] = base1
seed[2] = base2
repeat galaxy7num-1 {
nextgalaxy7()
}
}
sub nextgalaxy7() {
seed[0] = twist(seed[0])
seed[1] = twist(seed[1])
seed[2] = twist(seed[2])
number++
if number==9
number = 1
}
sub travel_to(ubyte galaxy7num, ubyte system) {
init(galaxy7num)
generate_next_planet7() ; always at least planet7 0 (separate to avoid repeat ubyte overflow)
repeat system {
generate_next_planet7()
}
planet7.name = make_current_planet7_name()
init_market7_for_planet7()
}
sub init_market7_for_planet7() {
market7.init(lsb(seed[0])+msb(seed[2]))
}
sub search_closest_planet7(uword nameptr) -> ubyte {
ubyte x = planet7.x
ubyte y = planet7.y
ubyte current_planet7_num = planet7.number
init(number)
ubyte found = false
ubyte current_closest_pi
ubyte current_distance = 127
ubyte pi
for pi in 0 to 255 {
generate_next_planet7()
planet7.name = make_current_planet7_name()
if util7.prefix_matches(nameptr, planet7.name) {
ubyte distance = planet7.distance(x, y)
if distance < current_distance {
current_distance = distance
current_closest_pi = pi
found = true
}
}
}
if found
travel_to(number, current_closest_pi)
else
travel_to(number, current_planet7_num)
return found
}
sub local_area() {
ubyte current_planet7 = planet7.number
ubyte px = planet7.x
ubyte py = planet7.y
ubyte pn = 0
init(number)
txt.print("\nGalaxy #")
txt.print_ub(number)
txt.print(" - systems in vicinity:\n")
do {
generate_next_planet7()
ubyte distance = planet7.distance(px, py)
if distance <= ship7.Max_fuel {
if distance <= ship7.fuel
txt.chrout('*')
else
txt.chrout('-')
txt.spc()
planet7.name = make_current_planet7_name()
planet7.display(true)
txt.print(" (")
util7.print_10s(distance)
txt.print(" LY)\n")
}
pn++
} until pn==0
travel_to(number, current_planet7)
}
ubyte pn_pair1
ubyte pn_pair2
ubyte pn_pair3
ubyte pn_pair4
ubyte longname
sub generate_next_planet7() {
determine_planet7_properties()
longname = lsb(seed[0]) & 64
; Always four iterations of random number
pn_pair1 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair2 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair3 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair4 = (msb(seed[2]) & 31) * 2
tweakseed()
}
sub make_current_planet7_name() -> str {
ubyte ni = 0
str name = " " ; max 8
if pn_pairs[pn_pair1] != '.' {
name[ni] = pn_pairs[pn_pair1]
ni++
}
if pn_pairs[pn_pair1+1] != '.' {
name[ni] = pn_pairs[pn_pair1+1]
ni++
}
if pn_pairs[pn_pair2] != '.' {
name[ni] = pn_pairs[pn_pair2]
ni++
}
if pn_pairs[pn_pair2+1] != '.' {
name[ni] = pn_pairs[pn_pair2+1]
ni++
}
if pn_pairs[pn_pair3] != '.' {
name[ni] = pn_pairs[pn_pair3]
ni++
}
if pn_pairs[pn_pair3+1] != '.' {
name[ni] = pn_pairs[pn_pair3+1]
ni++
}
if longname {
if pn_pairs[pn_pair4] != '.' {
name[ni] = pn_pairs[pn_pair4]
ni++
}
if pn_pairs[pn_pair4+1] != '.' {
name[ni] = pn_pairs[pn_pair4+1]
ni++
}
}
name[ni] = 0
return name
}
sub determine_planet7_properties() {
; create the planet7's characteristics
planet7.number++
planet7.x = msb(seed[1])
planet7.y = msb(seed[0])
planet7.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
planet7.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
if planet7.govtype <= 1
planet7.economy = (planet7.economy | 2)
planet7.techlevel = (msb(seed[1]) & 3) + (planet7.economy ^ 7)
planet7.techlevel += planet7.govtype >> 1
if planet7.govtype & 1
planet7.techlevel++
planet7.population = 4 * planet7.techlevel + planet7.economy
planet7.population += planet7.govtype + 1
planet7.productivity = ((planet7.economy ^ 7) + 3) * (planet7.govtype + 4)
planet7.productivity *= planet7.population * 8
ubyte seed2_msb = msb(seed[2])
planet7.radius = mkword((seed2_msb & 15) + 11, planet7.x)
planet7.species_is_alien = lsb(seed[2]) & 128 ; bit 7 of w2_lo
if planet7.species_is_alien {
planet7.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
planet7.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
planet7.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
planet7.species_kind = (planet7.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
}
planet7.goatsoup_seed[0] = lsb(seed[1])
planet7.goatsoup_seed[1] = msb(seed[1])
planet7.goatsoup_seed[2] = lsb(seed[2])
planet7.goatsoup_seed[3] = seed2_msb
}
sub tweakseed() {
uword temp = seed[0] + seed[1] + seed[2]
seed[0] = seed[1]
seed[1] = seed[2]
seed[2] = temp
}
sub twist(uword x) -> uword {
ubyte xh = msb(x)
ubyte xl = lsb(x)
rol(xh)
rol(xl)
return mkword(xh, xl)
}
sub debug_seed() {
txt.print("\ngalaxy7 #")
txt.print_ub(number)
txt.print("\ngalaxy7 seed0=")
txt.print_uwhex(galaxy7.seed[0], true)
txt.print("\ngalaxy7 seed1=")
txt.print_uwhex(galaxy7.seed[1], true)
txt.print("\ngalaxy7 seed2=")
txt.print_uwhex(galaxy7.seed[2], true)
txt.nl()
}
}
planet7 {
%option force_output
str[] species_sizes = ["Large", "Fierce", "Small"]
str[] species_colors = ["Green", "Red", "Yellow", "Blue", "Black", "Harmless"]
str[] species_looks = ["Slimy", "Bug-Eyed", "Horned", "Bony", "Fat", "Furry"]
str[] species_kinds = ["Rodents", "Frogs", "Lizards", "Lobsters", "Birds", "Humanoids", "Felines", "Insects"]
str[] govnames = ["Anarchy", "Feudal", "Multi-gov", "Dictatorship7", "Communist", "Confederacy", "Democracy", "Corporate State"]
str[] econnames = ["Rich Industrial", "Average Industrial", "Poor Industrial", "Mainly Industrial",
"Mainly Agricultural", "Rich Agricultural", "Average Agricultural", "Poor Agricultural"]
str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
str[] words82 = ["very", "mildly", "most", "reasonably", ""]
str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
str[] words8F = ["\xB0", "The planet7 \xB0", "The world \xB0", "This planet7", "This world"]
str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
str[] words91 = ["planet7", "world", "place", "little planet7", "dump"]
str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
uword[] wordlists = [
words81, words82, words83, words84, words85, words86, words87, words88,
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
words91, words92, words93, words94, words95, words96, words97, words98,
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
wordsA1, wordsA2, wordsA3, wordsA4]
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
str name = " " ; 8 max
ubyte number ; starts at 0 in new galaxy7, then increases by 1 for each generated planet7
ubyte x
ubyte y
ubyte economy
ubyte govtype
ubyte techlevel
ubyte population
uword productivity
uword radius
ubyte species_is_alien ; otherwise "Human Colonials"
ubyte species_size
ubyte species_color
ubyte species_look
ubyte species_kind
sub set_seed(uword s1, uword s2) {
goatsoup_seed[0] = lsb(s1)
goatsoup_seed[1] = msb(s1)
goatsoup_seed[2] = lsb(s2)
goatsoup_seed[3] = msb(s2)
reset_rnd()
}
sub reset_rnd() {
goatsoup_rnd[0] = goatsoup_seed[0]
goatsoup_rnd[1] = goatsoup_seed[1]
goatsoup_rnd[2] = goatsoup_seed[2]
goatsoup_rnd[3] = goatsoup_seed[3]
}
sub random_name() -> str {
ubyte ii
str name = " " ; 8 chars max
ubyte nx = 0
for ii in 0 to goatsoup_rnd_number() & 3 {
ubyte x = goatsoup_rnd_number() & $3e
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
x++
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
}
name[nx] = 0
name[0] |= 32 ; uppercase first letter
return name
}
sub goatsoup_rnd_number() -> ubyte {
ubyte x = goatsoup_rnd[0] * 2
uword a = x as uword + goatsoup_rnd[2]
if goatsoup_rnd[0] > 127
a ++
goatsoup_rnd[0] = lsb(a)
goatsoup_rnd[2] = x
x = goatsoup_rnd[1]
ubyte ac = x + goatsoup_rnd[3] + msb(a)
goatsoup_rnd[1] = ac
goatsoup_rnd[3] = x
return ac
}
sub distance(ubyte px, ubyte py) -> ubyte {
uword ax
uword ay
if px>x
ax=px-x
else
ax=x-px
if py>y
ay=py-y
else
ay=y-py
ay /= 2
ubyte d = sqrt16(ax*ax + ay*ay)
if d>63
return 255
return d*4
}
sub soup() -> str {
str planet7_result = " " * 160
uword[6] source_stack
ubyte stack_ptr = 0
str start_source = "\x8F is \x97."
uword source_ptr = &start_source
uword result_ptr = &planet7_result
reset_rnd()
recursive_soup()
return planet7_result
sub recursive_soup() {
repeat {
ubyte c = @(source_ptr)
source_ptr++
if c == $00 {
@(result_ptr) = 0
return
}
else if c <= $80 {
@(result_ptr) = c
result_ptr++
}
else {
if c <= $a4 {
ubyte rnr = goatsoup_rnd_number()
ubyte wordNr = (rnr >= $33) + (rnr >= $66) + (rnr >= $99) + (rnr >= $CC)
source_stack[stack_ptr] = source_ptr
stack_ptr++
source_ptr = getword(c, wordNr)
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
stack_ptr--
source_ptr = source_stack[stack_ptr]
} else {
if c == $b0 {
@(result_ptr) = name[0] | 32
result_ptr++
concat_string(&name + 1)
}
else if c == $b1 {
@(result_ptr) = name[0] | 32
result_ptr++
ubyte ni
for ni in 1 to len(name) {
ubyte cc = name[ni]
if cc=='e' or cc=='o' or cc==0
break
else {
@(result_ptr) = cc
result_ptr++
}
}
@(result_ptr) = 'i'
result_ptr++
@(result_ptr) = 'a'
result_ptr++
@(result_ptr) = 'n'
result_ptr++
}
else if c == $b2 {
concat_string(random_name())
}
else {
@(result_ptr) = c
result_ptr++
}
}
}
}
}
sub concat_string(uword str_ptr) {
repeat {
ubyte c = @(str_ptr)
if c==0
break
else {
@(result_ptr) = c
str_ptr++
result_ptr++
}
}
}
}
sub display(ubyte compressed) {
if compressed {
print_name_uppercase()
txt.print(" TL:")
txt.print_ub(techlevel+1)
txt.spc()
txt.print(econnames[economy])
txt.spc()
txt.print(govnames[govtype])
} else {
txt.print("\n\nSystem: ")
print_name_uppercase()
txt.print("\nPosition: ")
txt.print_ub(x)
txt.chrout('\'')
txt.print_ub(y)
txt.spc()
txt.chrout('#')
txt.print_ub(number)
txt.print("\nEconomy: ")
txt.print(econnames[economy])
txt.print("\nGovernment: ")
txt.print(govnames[govtype])
txt.print("\nTech Level: ")
txt.print_ub(techlevel+1)
txt.print("\nTurnover: ")
txt.print_uw(productivity)
txt.print("\nRadius: ")
txt.print_uw(radius)
txt.print("\nPopulation: ")
txt.print_ub(population >> 3)
txt.print(" Billion\nSpecies: ")
if species_is_alien {
if species_size < len(species_sizes) {
txt.print(species_sizes[species_size])
txt.spc()
}
if species_color < len(species_colors) {
txt.print(species_colors[species_color])
txt.spc()
}
if species_look < len(species_looks) {
txt.print(species_looks[species_look])
txt.spc()
}
if species_kind < len(species_kinds) {
txt.print(species_kinds[species_kind])
}
} else {
txt.print("Human Colonials")
}
txt.nl()
txt.print(soup())
txt.nl()
}
}
sub print_name_uppercase() {
ubyte c
for c in name
txt.chrout(c | 32)
}
asmsub getword(ubyte list @A, ubyte wordidx @Y) -> uword @AY {
%asm {{
sty P8ZP_SCRATCH_REG
sec
sbc #$81
asl a
tay
lda wordlists,y
sta P8ZP_SCRATCH_W1
lda wordlists+1,y
sta P8ZP_SCRATCH_W1+1
lda P8ZP_SCRATCH_REG
asl a
tay
lda (P8ZP_SCRATCH_W1),y
pha
iny
lda (P8ZP_SCRATCH_W1),y
tay
pla
rts
}}
}
}
util7 {
sub prefix_matches(uword prefixptr, uword stringptr) -> ubyte {
repeat {
ubyte pc = @(prefixptr)
ubyte sc = @(stringptr)
if pc == 0
return true
; to lowercase for case insensitive compare:
pc &= 127
sc &= 127
if pc != sc
return false
prefixptr++
stringptr++
}
return false
}
sub print_right(ubyte width, uword st) {
repeat width - string.length(st) {
txt.spc()
}
txt.print(st)
}
asmsub print_10s(uword value @AY) clobbers(A, X, Y) {
%asm {{
jsr conv.uword2decimal
lda conv.uword2decimal.decTenThousands
ldy #0 ; have we started printing?
cmp #'0'
beq +
jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decThousands
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decHundreds
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decTens
jsr c64.CHROUT
lda #'.'
jsr c64.CHROUT
lda conv.uword2decimal.decOnes
jsr c64.CHROUT
rts
}}
}
}

View File

@ -1,994 +0,0 @@
%import textio
%import conv
%import diskio
%import string
%import test_stack
%option no_sysinit
%zeropage basicsafe
; Prog8 adaptation of the Text-Elite galaxy8 system trading simulation engine.
; Original C-version obtained from: http://www.elitehomepage.org/text/index.htm
; Note: this program is compatible with C64 and CX16.
perf8 {
const ubyte numforLave = 7 ; Lave is 7th generated planet8 in galaxy8 one
const ubyte numforZaonce = 129
const ubyte numforDiso = 147
const ubyte numforRiedquat = 46
sub start() {
txt.lowercase()
txt.print("\u000c\n --- TextElite v1.1 ---\n")
galaxy8.travel_to(1, numforLave)
market8.init(0) ; Lave's market8 is seeded with 0
ship8.init()
planet8.display(false)
repeat {
; test_stack.test()
str input = "????????"
txt.print("\nCash: ")
util8.print_10s(ship8.cash)
txt.print("\nCommand (?=help): ")
ubyte num_chars = txt.input_chars(input)
txt.nl()
if num_chars {
when input[0] {
'?' -> {
txt.print("\nCommands are:\n"+
"buy jump info cash >=save\n"+
"sell teleport market8 hold <=load\n"+
"fuel galhyp local quit\n")
}
'q' -> break
'b' -> trader8.do_buy()
's' -> trader8.do_sell()
'f' -> trader8.do_fuel()
'j' -> trader8.do_jump()
't' -> trader8.do_teleport()
'g' -> trader8.do_next_galaxy8()
'i' -> trader8.do_info()
'm' -> trader8.do_show_market8()
'l' -> trader8.do_local()
'c' -> trader8.do_cash()
'h' -> trader8.do_hold()
'<' -> trader8.do_load()
'>' -> trader8.do_save()
}
}
}
}
}
trader8 {
str Savegame = "↑commander.save"
str input = "??????????"
ubyte num_chars
struct SaveData {
ubyte galaxy8
ubyte planet8
ubyte cargo0
ubyte cargo1
ubyte cargo2
ubyte cargo3
ubyte cargo4
ubyte cargo5
ubyte cargo6
ubyte cargo7
ubyte cargo8
ubyte cargo9
ubyte cargo10
ubyte cargo11
ubyte cargo12
ubyte cargo13
ubyte cargo14
ubyte cargo15
ubyte cargo16
uword cash
ubyte max_cargo
ubyte fuel
}
SaveData savedata
sub do_load() {
txt.print("\nLoading universe...")
if diskio.load(8, Savegame, &savedata) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
return
}
ship8.cash = savedata.cash
ship8.Max_cargo = savedata.max_cargo
ship8.fuel = savedata.fuel
sys.memcopy(&savedata.cargo0, ship8.cargohold, len(ship8.cargohold))
galaxy8.travel_to(savedata.galaxy8, savedata.planet8)
planet8.display(false)
}
sub do_save() {
savedata.galaxy8 = galaxy8.number
savedata.planet8 = planet8.number
savedata.cash = ship8.cash
savedata.max_cargo = ship8.Max_cargo
savedata.fuel = ship8.fuel
sys.memcopy(ship8.cargohold, &savedata.cargo0, len(ship8.cargohold))
txt.print("\nSaving universe...")
diskio.delete(8, Savegame)
if diskio.save(8, Savegame, &savedata, sizeof(savedata)) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
}
}
sub do_jump() {
txt.print("\nJump to what system? ")
jump_to_system()
}
sub do_teleport() {
txt.print("\nCheat! Teleport to what system? ")
ubyte fuel = ship8.fuel
ship8.fuel = 255
jump_to_system()
ship8.fuel = fuel
}
sub jump_to_system() {
void txt.input_chars(input)
ubyte current_planet8 = planet8.number
ubyte x = planet8.x
ubyte y = planet8.y
if galaxy8.search_closest_planet8(input) {
ubyte distance = planet8.distance(x, y)
if distance <= ship8.fuel {
galaxy8.init_market8_for_planet8()
ship8.fuel -= distance
txt.print("\n\nHyperspace jump! Arrived at:\n")
planet8.display(true)
return
}
txt.print("Insufficient fuel\n")
} else {
txt.print(" Not found!\n")
}
galaxy8.travel_to(galaxy8.number, current_planet8)
}
sub do_buy() {
txt.print("\nBuy what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market8.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if market8.current_quantity[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market8.current_price[ci] * amount
txt.print(" Total price: ")
util8.print_10s(price)
if price > ship8.cash {
txt.print(" Not enough cash!\n")
} else {
ship8.cash -= price
ship8.cargohold[ci] += amount
market8.current_quantity[ci] -= amount
}
}
}
}
sub do_sell() {
txt.print("\nSell what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market8.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if ship8.cargohold[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market8.current_price[ci] * amount
txt.print(" Total price: ")
util8.print_10s(price)
ship8.cash += price
ship8.cargohold[ci] -= amount
market8.current_quantity[ci] += amount
}
}
}
sub do_fuel() {
txt.print("\nBuy fuel. Amount? ")
void txt.input_chars(input)
ubyte buy_fuel = 10*conv.str2ubyte(input)
ubyte max_fuel = ship8.Max_fuel - ship8.fuel
if buy_fuel > max_fuel
buy_fuel = max_fuel
uword price = buy_fuel as uword * ship8.Fuel_cost
if price > ship8.cash {
txt.print("Not enough cash!\n")
} else {
ship8.cash -= price
ship8.fuel += buy_fuel
}
}
sub do_cash() {
txt.print("\nCheat! Set cash amount: ")
void txt.input_chars(input)
ship8.cash = conv.str2uword(input)
}
sub do_hold() {
txt.print("\nCheat! Set cargohold size: ")
void txt.input_chars(input)
ship8.Max_cargo = conv.str2ubyte(input)
}
sub do_next_galaxy8() {
galaxy8.travel_to(galaxy8.number+1, planet8.number)
planet8.display(false)
}
sub do_info() {
txt.print("\nSystem name (empty=current): ")
num_chars = txt.input_chars(input)
if num_chars {
ubyte current_planet8 = planet8.number
if galaxy8.search_closest_planet8(input) {
planet8.display(false)
} else {
txt.print(" Not found!")
}
galaxy8.travel_to(galaxy8.number, current_planet8)
} else {
planet8.display(false)
}
}
sub do_local() {
galaxy8.local_area()
}
sub do_show_market8() {
market8.display()
txt.print("\nFuel: ")
util8.print_10s(ship8.fuel)
txt.print(" Cargohold space: ")
txt.print_ub(ship8.cargo_free())
txt.print("t\n")
}
}
ship8 {
const ubyte Max_fuel = 70
const ubyte Fuel_cost = 2
ubyte Max_cargo = 20
ubyte fuel = Max_fuel
uword cash = 1000 ; actually has to be 4 bytes for the ultra rich....
ubyte[17] cargohold = 0
sub init() {
sys.memset(cargohold, len(cargohold), 0)
}
sub cargo_free() -> ubyte {
ubyte ci
ubyte total = 0
for ci in 0 to len(cargohold)-1 {
if market8.units[ci]==0 ; tonnes only
total += cargohold[ci]
}
return Max_cargo - total
}
}
market8 {
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
ubyte[17] units = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0]
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
ubyte[17] current_quantity = 0
uword[17] current_price = 0
sub init(ubyte fluct) {
; Prices and availabilities are influenced by the planet8's economy type
; (0-7) and a random "fluctuation" byte that was kept within the saved
; commander position to keep the market8 prices constant over gamesaves.
; Availabilities must be saved with the game since the player alters them
; by buying (and selling(?))
;
; Almost all operations are one byte only and overflow "errors" are
; extremely frequent and exploited.
;
; Trade Item prices are held internally in a single byte=true value/4.
; The decimal point in prices is introduced only when printing them.
; Internally, all prices are integers.
; The player's cash is held in four bytes.
ubyte ci
for ci in 0 to len(names)-1 {
word product
byte changing
product = planet8.economy as word * gradients[ci]
changing = fluct & maskbytes[ci] as byte
ubyte q = (basequants[ci] as word + changing - product) as ubyte
if q & $80
q = 0 ; clip to positive 8-bit
current_quantity[ci] = q & $3f
q = (baseprices[ci] + changing + product) as ubyte
current_price[ci] = q * $0004
}
current_quantity[16] = 0 ; force nonavailability of Alien Items
}
sub display() {
ubyte ci
txt.nl()
planet8.print_name_uppercase()
txt.print(" trade market8:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
for ci in 0 to len(names)-1 {
util8.print_right(13, names[ci])
txt.print(" ")
util8.print_10s(current_price[ci])
txt.print(" ")
txt.print_ub(current_quantity[ci])
when units[ci] {
0 -> txt.chrout('t')
1 -> txt.print("kg")
2 -> txt.chrout('g')
}
txt.print(" ")
txt.print_ub(ship8.cargohold[ci])
txt.nl()
}
}
sub match(uword nameptr) -> ubyte {
ubyte ci
for ci in 0 to len(names)-1 {
if util8.prefix_matches(nameptr, names[ci])
return ci
}
return 255
}
}
galaxy8 {
const uword GALSIZE = 256
const uword base0 = $5A4A ; seeds for the first galaxy8
const uword base1 = $0248
const uword base2 = $B753
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
ubyte number
uword[3] seed
sub init(ubyte galaxy8num) {
number = 1
planet8.number = 255
seed[0] = base0
seed[1] = base1
seed[2] = base2
repeat galaxy8num-1 {
nextgalaxy8()
}
}
sub nextgalaxy8() {
seed[0] = twist(seed[0])
seed[1] = twist(seed[1])
seed[2] = twist(seed[2])
number++
if number==9
number = 1
}
sub travel_to(ubyte galaxy8num, ubyte system) {
init(galaxy8num)
generate_next_planet8() ; always at least planet8 0 (separate to avoid repeat ubyte overflow)
repeat system {
generate_next_planet8()
}
planet8.name = make_current_planet8_name()
init_market8_for_planet8()
}
sub init_market8_for_planet8() {
market8.init(lsb(seed[0])+msb(seed[2]))
}
sub search_closest_planet8(uword nameptr) -> ubyte {
ubyte x = planet8.x
ubyte y = planet8.y
ubyte current_planet8_num = planet8.number
init(number)
ubyte found = false
ubyte current_closest_pi
ubyte current_distance = 127
ubyte pi
for pi in 0 to 255 {
generate_next_planet8()
planet8.name = make_current_planet8_name()
if util8.prefix_matches(nameptr, planet8.name) {
ubyte distance = planet8.distance(x, y)
if distance < current_distance {
current_distance = distance
current_closest_pi = pi
found = true
}
}
}
if found
travel_to(number, current_closest_pi)
else
travel_to(number, current_planet8_num)
return found
}
sub local_area() {
ubyte current_planet8 = planet8.number
ubyte px = planet8.x
ubyte py = planet8.y
ubyte pn = 0
init(number)
txt.print("\nGalaxy #")
txt.print_ub(number)
txt.print(" - systems in vicinity:\n")
do {
generate_next_planet8()
ubyte distance = planet8.distance(px, py)
if distance <= ship8.Max_fuel {
if distance <= ship8.fuel
txt.chrout('*')
else
txt.chrout('-')
txt.spc()
planet8.name = make_current_planet8_name()
planet8.display(true)
txt.print(" (")
util8.print_10s(distance)
txt.print(" LY)\n")
}
pn++
} until pn==0
travel_to(number, current_planet8)
}
ubyte pn_pair1
ubyte pn_pair2
ubyte pn_pair3
ubyte pn_pair4
ubyte longname
sub generate_next_planet8() {
determine_planet8_properties()
longname = lsb(seed[0]) & 64
; Always four iterations of random number
pn_pair1 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair2 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair3 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair4 = (msb(seed[2]) & 31) * 2
tweakseed()
}
sub make_current_planet8_name() -> str {
ubyte ni = 0
str name = " " ; max 8
if pn_pairs[pn_pair1] != '.' {
name[ni] = pn_pairs[pn_pair1]
ni++
}
if pn_pairs[pn_pair1+1] != '.' {
name[ni] = pn_pairs[pn_pair1+1]
ni++
}
if pn_pairs[pn_pair2] != '.' {
name[ni] = pn_pairs[pn_pair2]
ni++
}
if pn_pairs[pn_pair2+1] != '.' {
name[ni] = pn_pairs[pn_pair2+1]
ni++
}
if pn_pairs[pn_pair3] != '.' {
name[ni] = pn_pairs[pn_pair3]
ni++
}
if pn_pairs[pn_pair3+1] != '.' {
name[ni] = pn_pairs[pn_pair3+1]
ni++
}
if longname {
if pn_pairs[pn_pair4] != '.' {
name[ni] = pn_pairs[pn_pair4]
ni++
}
if pn_pairs[pn_pair4+1] != '.' {
name[ni] = pn_pairs[pn_pair4+1]
ni++
}
}
name[ni] = 0
return name
}
sub determine_planet8_properties() {
; create the planet8's characteristics
planet8.number++
planet8.x = msb(seed[1])
planet8.y = msb(seed[0])
planet8.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
planet8.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
if planet8.govtype <= 1
planet8.economy = (planet8.economy | 2)
planet8.techlevel = (msb(seed[1]) & 3) + (planet8.economy ^ 7)
planet8.techlevel += planet8.govtype >> 1
if planet8.govtype & 1
planet8.techlevel++
planet8.population = 4 * planet8.techlevel + planet8.economy
planet8.population += planet8.govtype + 1
planet8.productivity = ((planet8.economy ^ 7) + 3) * (planet8.govtype + 4)
planet8.productivity *= planet8.population * 8
ubyte seed2_msb = msb(seed[2])
planet8.radius = mkword((seed2_msb & 15) + 11, planet8.x)
planet8.species_is_alien = lsb(seed[2]) & 128 ; bit 7 of w2_lo
if planet8.species_is_alien {
planet8.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
planet8.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
planet8.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
planet8.species_kind = (planet8.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
}
planet8.goatsoup_seed[0] = lsb(seed[1])
planet8.goatsoup_seed[1] = msb(seed[1])
planet8.goatsoup_seed[2] = lsb(seed[2])
planet8.goatsoup_seed[3] = seed2_msb
}
sub tweakseed() {
uword temp = seed[0] + seed[1] + seed[2]
seed[0] = seed[1]
seed[1] = seed[2]
seed[2] = temp
}
sub twist(uword x) -> uword {
ubyte xh = msb(x)
ubyte xl = lsb(x)
rol(xh)
rol(xl)
return mkword(xh, xl)
}
sub debug_seed() {
txt.print("\ngalaxy8 #")
txt.print_ub(number)
txt.print("\ngalaxy8 seed0=")
txt.print_uwhex(galaxy8.seed[0], true)
txt.print("\ngalaxy8 seed1=")
txt.print_uwhex(galaxy8.seed[1], true)
txt.print("\ngalaxy8 seed2=")
txt.print_uwhex(galaxy8.seed[2], true)
txt.nl()
}
}
planet8 {
%option force_output
str[] species_sizes = ["Large", "Fierce", "Small"]
str[] species_colors = ["Green", "Red", "Yellow", "Blue", "Black", "Harmless"]
str[] species_looks = ["Slimy", "Bug-Eyed", "Horned", "Bony", "Fat", "Furry"]
str[] species_kinds = ["Rodents", "Frogs", "Lizards", "Lobsters", "Birds", "Humanoids", "Felines", "Insects"]
str[] govnames = ["Anarchy", "Feudal", "Multi-gov", "Dictatorship8", "Communist", "Confederacy", "Democracy", "Corporate State"]
str[] econnames = ["Rich Industrial", "Average Industrial", "Poor Industrial", "Mainly Industrial",
"Mainly Agricultural", "Rich Agricultural", "Average Agricultural", "Poor Agricultural"]
str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
str[] words82 = ["very", "mildly", "most", "reasonably", ""]
str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
str[] words8F = ["\xB0", "The planet8 \xB0", "The world \xB0", "This planet8", "This world"]
str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
str[] words91 = ["planet8", "world", "place", "little planet8", "dump"]
str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
uword[] wordlists = [
words81, words82, words83, words84, words85, words86, words87, words88,
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
words91, words92, words93, words94, words95, words96, words97, words98,
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
wordsA1, wordsA2, wordsA3, wordsA4]
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
str name = " " ; 8 max
ubyte number ; starts at 0 in new galaxy8, then increases by 1 for each generated planet8
ubyte x
ubyte y
ubyte economy
ubyte govtype
ubyte techlevel
ubyte population
uword productivity
uword radius
ubyte species_is_alien ; otherwise "Human Colonials"
ubyte species_size
ubyte species_color
ubyte species_look
ubyte species_kind
sub set_seed(uword s1, uword s2) {
goatsoup_seed[0] = lsb(s1)
goatsoup_seed[1] = msb(s1)
goatsoup_seed[2] = lsb(s2)
goatsoup_seed[3] = msb(s2)
reset_rnd()
}
sub reset_rnd() {
goatsoup_rnd[0] = goatsoup_seed[0]
goatsoup_rnd[1] = goatsoup_seed[1]
goatsoup_rnd[2] = goatsoup_seed[2]
goatsoup_rnd[3] = goatsoup_seed[3]
}
sub random_name() -> str {
ubyte ii
str name = " " ; 8 chars max
ubyte nx = 0
for ii in 0 to goatsoup_rnd_number() & 3 {
ubyte x = goatsoup_rnd_number() & $3e
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
x++
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
}
name[nx] = 0
name[0] |= 32 ; uppercase first letter
return name
}
sub goatsoup_rnd_number() -> ubyte {
ubyte x = goatsoup_rnd[0] * 2
uword a = x as uword + goatsoup_rnd[2]
if goatsoup_rnd[0] > 127
a ++
goatsoup_rnd[0] = lsb(a)
goatsoup_rnd[2] = x
x = goatsoup_rnd[1]
ubyte ac = x + goatsoup_rnd[3] + msb(a)
goatsoup_rnd[1] = ac
goatsoup_rnd[3] = x
return ac
}
sub distance(ubyte px, ubyte py) -> ubyte {
uword ax
uword ay
if px>x
ax=px-x
else
ax=x-px
if py>y
ay=py-y
else
ay=y-py
ay /= 2
ubyte d = sqrt16(ax*ax + ay*ay)
if d>63
return 255
return d*4
}
sub soup() -> str {
str planet8_result = " " * 160
uword[6] source_stack
ubyte stack_ptr = 0
str start_source = "\x8F is \x97."
uword source_ptr = &start_source
uword result_ptr = &planet8_result
reset_rnd()
recursive_soup()
return planet8_result
sub recursive_soup() {
repeat {
ubyte c = @(source_ptr)
source_ptr++
if c == $00 {
@(result_ptr) = 0
return
}
else if c <= $80 {
@(result_ptr) = c
result_ptr++
}
else {
if c <= $a4 {
ubyte rnr = goatsoup_rnd_number()
ubyte wordNr = (rnr >= $33) + (rnr >= $66) + (rnr >= $99) + (rnr >= $CC)
source_stack[stack_ptr] = source_ptr
stack_ptr++
source_ptr = getword(c, wordNr)
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
stack_ptr--
source_ptr = source_stack[stack_ptr]
} else {
if c == $b0 {
@(result_ptr) = name[0] | 32
result_ptr++
concat_string(&name + 1)
}
else if c == $b1 {
@(result_ptr) = name[0] | 32
result_ptr++
ubyte ni
for ni in 1 to len(name) {
ubyte cc = name[ni]
if cc=='e' or cc=='o' or cc==0
break
else {
@(result_ptr) = cc
result_ptr++
}
}
@(result_ptr) = 'i'
result_ptr++
@(result_ptr) = 'a'
result_ptr++
@(result_ptr) = 'n'
result_ptr++
}
else if c == $b2 {
concat_string(random_name())
}
else {
@(result_ptr) = c
result_ptr++
}
}
}
}
}
sub concat_string(uword str_ptr) {
repeat {
ubyte c = @(str_ptr)
if c==0
break
else {
@(result_ptr) = c
str_ptr++
result_ptr++
}
}
}
}
sub display(ubyte compressed) {
if compressed {
print_name_uppercase()
txt.print(" TL:")
txt.print_ub(techlevel+1)
txt.spc()
txt.print(econnames[economy])
txt.spc()
txt.print(govnames[govtype])
} else {
txt.print("\n\nSystem: ")
print_name_uppercase()
txt.print("\nPosition: ")
txt.print_ub(x)
txt.chrout('\'')
txt.print_ub(y)
txt.spc()
txt.chrout('#')
txt.print_ub(number)
txt.print("\nEconomy: ")
txt.print(econnames[economy])
txt.print("\nGovernment: ")
txt.print(govnames[govtype])
txt.print("\nTech Level: ")
txt.print_ub(techlevel+1)
txt.print("\nTurnover: ")
txt.print_uw(productivity)
txt.print("\nRadius: ")
txt.print_uw(radius)
txt.print("\nPopulation: ")
txt.print_ub(population >> 3)
txt.print(" Billion\nSpecies: ")
if species_is_alien {
if species_size < len(species_sizes) {
txt.print(species_sizes[species_size])
txt.spc()
}
if species_color < len(species_colors) {
txt.print(species_colors[species_color])
txt.spc()
}
if species_look < len(species_looks) {
txt.print(species_looks[species_look])
txt.spc()
}
if species_kind < len(species_kinds) {
txt.print(species_kinds[species_kind])
}
} else {
txt.print("Human Colonials")
}
txt.nl()
txt.print(soup())
txt.nl()
}
}
sub print_name_uppercase() {
ubyte c
for c in name
txt.chrout(c | 32)
}
asmsub getword(ubyte list @A, ubyte wordidx @Y) -> uword @AY {
%asm {{
sty P8ZP_SCRATCH_REG
sec
sbc #$81
asl a
tay
lda wordlists,y
sta P8ZP_SCRATCH_W1
lda wordlists+1,y
sta P8ZP_SCRATCH_W1+1
lda P8ZP_SCRATCH_REG
asl a
tay
lda (P8ZP_SCRATCH_W1),y
pha
iny
lda (P8ZP_SCRATCH_W1),y
tay
pla
rts
}}
}
}
util8 {
sub prefix_matches(uword prefixptr, uword stringptr) -> ubyte {
repeat {
ubyte pc = @(prefixptr)
ubyte sc = @(stringptr)
if pc == 0
return true
; to lowercase for case insensitive compare:
pc &= 127
sc &= 127
if pc != sc
return false
prefixptr++
stringptr++
}
return false
}
sub print_right(ubyte width, uword st) {
repeat width - string.length(st) {
txt.spc()
}
txt.print(st)
}
asmsub print_10s(uword value @AY) clobbers(A, X, Y) {
%asm {{
jsr conv.uword2decimal
lda conv.uword2decimal.decTenThousands
ldy #0 ; have we started printing?
cmp #'0'
beq +
jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decThousands
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decHundreds
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decTens
jsr c64.CHROUT
lda #'.'
jsr c64.CHROUT
lda conv.uword2decimal.decOnes
jsr c64.CHROUT
rts
}}
}
}

View File

@ -1,993 +0,0 @@
%import textio
%import conv
%import diskio
%import string
%import test_stack
%option no_sysinit
%zeropage basicsafe
; Prog8 adaptation of the Text-Elite galaxy9 system trading simulation engine.
; Original C-version obtained from: http://www.elitehomepage.org/text/index.htm
; Note: this program is compatible with C64 and CX16.
perf9 {
const ubyte numforLave = 7 ; Lave is 7th generated planet9 in galaxy9 one
const ubyte numforZaonce = 129
const ubyte numforDiso = 147
const ubyte numforRiedquat = 46
sub start() {
txt.lowercase()
txt.print("\u000c\n --- TextElite v1.1 ---\n")
galaxy9.travel_to(1, numforLave)
market9.init(0) ; Lave's market9 is seeded with 0
ship9.init()
planet9.display(false)
repeat {
; test_stack.test()
str input = "????????"
txt.print("\nCash: ")
util9.print_10s(ship9.cash)
txt.print("\nCommand (?=help): ")
ubyte num_chars = txt.input_chars(input)
txt.nl()
if num_chars {
when input[0] {
'?' -> {
txt.print("\nCommands are:\n"+
"buy jump info cash >=save\n"+
"sell teleport market9 hold <=load\n"+
"fuel galhyp local quit\n")
}
'q' -> break
'b' -> trader9.do_buy()
's' -> trader9.do_sell()
'f' -> trader9.do_fuel()
'j' -> trader9.do_jump()
't' -> trader9.do_teleport()
'g' -> trader9.do_next_galaxy9()
'i' -> trader9.do_info()
'm' -> trader9.do_show_market9()
'l' -> trader9.do_local()
'c' -> trader9.do_cash()
'h' -> trader9.do_hold()
'<' -> trader9.do_load()
'>' -> trader9.do_save()
}
}
}
}
}
trader9 {
str Savegame = "↑commander.save"
str input = "??????????"
ubyte num_chars
struct SaveData {
ubyte galaxy9
ubyte planet9
ubyte cargo0
ubyte cargo1
ubyte cargo2
ubyte cargo3
ubyte cargo4
ubyte cargo5
ubyte cargo6
ubyte cargo7
ubyte cargo8
ubyte cargo9
ubyte cargo10
ubyte cargo11
ubyte cargo12
ubyte cargo13
ubyte cargo14
ubyte cargo15
ubyte cargo16
uword cash
ubyte max_cargo
ubyte fuel
}
SaveData savedata
sub do_load() {
txt.print("\nLoading universe...")
if diskio.load(8, Savegame, &savedata) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
return
}
ship9.cash = savedata.cash
ship9.Max_cargo = savedata.max_cargo
ship9.fuel = savedata.fuel
sys.memcopy(&savedata.cargo0, ship9.cargohold, len(ship9.cargohold))
galaxy9.travel_to(savedata.galaxy9, savedata.planet9)
planet9.display(false)
}
sub do_save() {
savedata.galaxy9 = galaxy9.number
savedata.planet9 = planet9.number
savedata.cash = ship9.cash
savedata.max_cargo = ship9.Max_cargo
savedata.fuel = ship9.fuel
sys.memcopy(ship9.cargohold, &savedata.cargo0, len(ship9.cargohold))
txt.print("\nSaving universe...")
diskio.delete(8, Savegame)
if diskio.save(8, Savegame, &savedata, sizeof(savedata)) {
txt.print("ok\n")
} else {
txt.print("\ni/o error: ")
txt.print(diskio.status(8))
txt.nl()
}
}
sub do_jump() {
txt.print("\nJump to what system? ")
jump_to_system()
}
sub do_teleport() {
txt.print("\nCheat! Teleport to what system? ")
ubyte fuel = ship9.fuel
ship9.fuel = 255
jump_to_system()
ship9.fuel = fuel
}
sub jump_to_system() {
void txt.input_chars(input)
ubyte current_planet9 = planet9.number
ubyte x = planet9.x
ubyte y = planet9.y
if galaxy9.search_closest_planet9(input) {
ubyte distance = planet9.distance(x, y)
if distance <= ship9.fuel {
galaxy9.init_market9_for_planet9()
ship9.fuel -= distance
txt.print("\n\nHyperspace jump! Arrived at:\n")
planet9.display(true)
return
}
txt.print("Insufficient fuel\n")
} else {
txt.print(" Not found!\n")
}
galaxy9.travel_to(galaxy9.number, current_planet9)
}
sub do_buy() {
txt.print("\nBuy what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market9.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if market9.current_quantity[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market9.current_price[ci] * amount
txt.print(" Total price: ")
util9.print_10s(price)
if price > ship9.cash {
txt.print(" Not enough cash!\n")
} else {
ship9.cash -= price
ship9.cargohold[ci] += amount
market9.current_quantity[ci] -= amount
}
}
}
}
sub do_sell() {
txt.print("\nSell what commodity? ")
str commodity = "???????????????"
void txt.input_chars(commodity)
ubyte ci = market9.match(commodity)
if ci & 128 {
txt.print("Unknown\n")
} else {
txt.print("\nHow much? ")
void txt.input_chars(input)
ubyte amount = conv.str2ubyte(input)
if ship9.cargohold[ci] < amount {
txt.print(" Insufficient supply!\n")
} else {
uword price = market9.current_price[ci] * amount
txt.print(" Total price: ")
util9.print_10s(price)
ship9.cash += price
ship9.cargohold[ci] -= amount
market9.current_quantity[ci] += amount
}
}
}
sub do_fuel() {
txt.print("\nBuy fuel. Amount? ")
void txt.input_chars(input)
ubyte buy_fuel = 10*conv.str2ubyte(input)
ubyte max_fuel = ship9.Max_fuel - ship9.fuel
if buy_fuel > max_fuel
buy_fuel = max_fuel
uword price = buy_fuel as uword * ship9.Fuel_cost
if price > ship9.cash {
txt.print("Not enough cash!\n")
} else {
ship9.cash -= price
ship9.fuel += buy_fuel
}
}
sub do_cash() {
txt.print("\nCheat! Set cash amount: ")
void txt.input_chars(input)
ship9.cash = conv.str2uword(input)
}
sub do_hold() {
txt.print("\nCheat! Set cargohold size: ")
void txt.input_chars(input)
ship9.Max_cargo = conv.str2ubyte(input)
}
sub do_next_galaxy9() {
galaxy9.travel_to(galaxy9.number+1, planet9.number)
planet9.display(false)
}
sub do_info() {
txt.print("\nSystem name (empty=current): ")
num_chars = txt.input_chars(input)
if num_chars {
ubyte current_planet9 = planet9.number
if galaxy9.search_closest_planet9(input) {
planet9.display(false)
} else {
txt.print(" Not found!")
}
galaxy9.travel_to(galaxy9.number, current_planet9)
} else {
planet9.display(false)
}
}
sub do_local() {
galaxy9.local_area()
}
sub do_show_market9() {
market9.display()
txt.print("\nFuel: ")
util9.print_10s(ship9.fuel)
txt.print(" Cargohold space: ")
txt.print_ub(ship9.cargo_free())
txt.print("t\n")
}
}
ship9 {
const ubyte Max_fuel = 70
const ubyte Fuel_cost = 2
ubyte Max_cargo = 20
ubyte fuel = Max_fuel
uword cash = 1000 ; actually has to be 4 bytes for the ultra rich....
ubyte[17] cargohold = 0
sub init() {
sys.memset(cargohold, len(cargohold), 0)
}
sub cargo_free() -> ubyte {
ubyte ci
ubyte total = 0
for ci in 0 to len(cargohold)-1 {
if market9.units[ci]==0 ; tonnes only
total += cargohold[ci]
}
return Max_cargo - total
}
}
market9 {
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
ubyte[17] units = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0]
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
ubyte[17] current_quantity = 0
uword[17] current_price = 0
sub init(ubyte fluct) {
; Prices and availabilities are influenced by the planet9's economy type
; (0-7) and a random "fluctuation" byte that was kept within the saved
; commander position to keep the market9 prices constant over gamesaves.
; Availabilities must be saved with the game since the player alters them
; by buying (and selling(?))
;
; Almost all operations are one byte only and overflow "errors" are
; extremely frequent and exploited.
;
; Trade Item prices are held internally in a single byte=true value/4.
; The decimal point in prices is introduced only when printing them.
; Internally, all prices are integers.
; The player's cash is held in four bytes.
ubyte ci
for ci in 0 to len(names)-1 {
word product
byte changing
product = planet9.economy as word * gradients[ci]
changing = fluct & maskbytes[ci] as byte
ubyte q = (basequants[ci] as word + changing - product) as ubyte
if q & $80
q = 0 ; clip to positive 8-bit
current_quantity[ci] = q & $3f
q = (baseprices[ci] + changing + product) as ubyte
current_price[ci] = q * $0004
}
current_quantity[16] = 0 ; force nonavailability of Alien Items
}
sub display() {
ubyte ci
txt.nl()
planet9.print_name_uppercase()
txt.print(" trade market9:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
for ci in 0 to len(names)-1 {
util9.print_right(13, names[ci])
txt.print(" ")
util9.print_10s(current_price[ci])
txt.print(" ")
txt.print_ub(current_quantity[ci])
when units[ci] {
0 -> txt.chrout('t')
1 -> txt.print("kg")
2 -> txt.chrout('g')
}
txt.print(" ")
txt.print_ub(ship9.cargohold[ci])
txt.nl()
}
}
sub match(uword nameptr) -> ubyte {
ubyte ci
for ci in 0 to len(names)-1 {
if util9.prefix_matches(nameptr, names[ci])
return ci
}
return 255
}
}
galaxy9 {
const uword GALSIZE = 256
const uword base0 = $5A4A ; seeds for the first galaxy9
const uword base1 = $0248
const uword base2 = $B753
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
ubyte number
uword[3] seed
sub init(ubyte galaxy9num) {
number = 1
planet9.number = 255
seed[0] = base0
seed[1] = base1
seed[2] = base2
repeat galaxy9num-1 {
nextgalaxy9()
}
}
sub nextgalaxy9() {
seed[0] = twist(seed[0])
seed[1] = twist(seed[1])
seed[2] = twist(seed[2])
number++
if number==9
number = 1
}
sub travel_to(ubyte galaxy9num, ubyte system) {
init(galaxy9num)
generate_next_planet9() ; always at least planet9 0 (separate to avoid repeat ubyte overflow)
repeat system {
generate_next_planet9()
}
planet9.name = make_current_planet9_name()
init_market9_for_planet9()
}
sub init_market9_for_planet9() {
market9.init(lsb(seed[0])+msb(seed[2]))
}
sub search_closest_planet9(uword nameptr) -> ubyte {
ubyte x = planet9.x
ubyte y = planet9.y
ubyte current_planet9_num = planet9.number
init(number)
ubyte found = false
ubyte current_closest_pi
ubyte current_distance = 127
ubyte pi
for pi in 0 to 255 {
generate_next_planet9()
planet9.name = make_current_planet9_name()
if util9.prefix_matches(nameptr, planet9.name) {
ubyte distance = planet9.distance(x, y)
if distance < current_distance {
current_distance = distance
current_closest_pi = pi
found = true
}
}
}
if found
travel_to(number, current_closest_pi)
else
travel_to(number, current_planet9_num)
return found
}
sub local_area() {
ubyte current_planet9 = planet9.number
ubyte px = planet9.x
ubyte py = planet9.y
ubyte pn = 0
init(number)
txt.print("\nGalaxy #")
txt.print_ub(number)
txt.print(" - systems in vicinity:\n")
do {
generate_next_planet9()
ubyte distance = planet9.distance(px, py)
if distance <= ship9.Max_fuel {
if distance <= ship9.fuel
txt.chrout('*')
else
txt.chrout('-')
txt.spc()
planet9.name = make_current_planet9_name()
planet9.display(true)
txt.print(" (")
util9.print_10s(distance)
txt.print(" LY)\n")
}
pn++
} until pn==0
travel_to(number, current_planet9)
}
ubyte pn_pair1
ubyte pn_pair2
ubyte pn_pair3
ubyte pn_pair4
ubyte longname
sub generate_next_planet9() {
determine_planet9_properties()
longname = lsb(seed[0]) & 64
; Always four iterations of random number
pn_pair1 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair2 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair3 = (msb(seed[2]) & 31) * 2
tweakseed()
pn_pair4 = (msb(seed[2]) & 31) * 2
tweakseed()
}
sub make_current_planet9_name() -> str {
ubyte ni = 0
str name = " " ; max 8
if pn_pairs[pn_pair1] != '.' {
name[ni] = pn_pairs[pn_pair1]
ni++
}
if pn_pairs[pn_pair1+1] != '.' {
name[ni] = pn_pairs[pn_pair1+1]
ni++
}
if pn_pairs[pn_pair2] != '.' {
name[ni] = pn_pairs[pn_pair2]
ni++
}
if pn_pairs[pn_pair2+1] != '.' {
name[ni] = pn_pairs[pn_pair2+1]
ni++
}
if pn_pairs[pn_pair3] != '.' {
name[ni] = pn_pairs[pn_pair3]
ni++
}
if pn_pairs[pn_pair3+1] != '.' {
name[ni] = pn_pairs[pn_pair3+1]
ni++
}
if longname {
if pn_pairs[pn_pair4] != '.' {
name[ni] = pn_pairs[pn_pair4]
ni++
}
if pn_pairs[pn_pair4+1] != '.' {
name[ni] = pn_pairs[pn_pair4+1]
ni++
}
}
name[ni] = 0
return name
}
sub determine_planet9_properties() {
; create the planet9's characteristics
planet9.number++
planet9.x = msb(seed[1])
planet9.y = msb(seed[0])
planet9.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
planet9.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
if planet9.govtype <= 1
planet9.economy = (planet9.economy | 2)
planet9.techlevel = (msb(seed[1]) & 3) + (planet9.economy ^ 7)
planet9.techlevel += planet9.govtype >> 1
if planet9.govtype & 1
planet9.techlevel++
planet9.population = 4 * planet9.techlevel + planet9.economy
planet9.population += planet9.govtype + 1
planet9.productivity = ((planet9.economy ^ 7) + 3) * (planet9.govtype + 4)
planet9.productivity *= planet9.population * 8
ubyte seed2_msb = msb(seed[2])
planet9.radius = mkword((seed2_msb & 15) + 11, planet9.x)
planet9.species_is_alien = lsb(seed[2]) & 128 ; bit 7 of w2_lo
if planet9.species_is_alien {
planet9.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
planet9.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
planet9.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
planet9.species_kind = (planet9.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
}
planet9.goatsoup_seed[0] = lsb(seed[1])
planet9.goatsoup_seed[1] = msb(seed[1])
planet9.goatsoup_seed[2] = lsb(seed[2])
planet9.goatsoup_seed[3] = seed2_msb
}
sub tweakseed() {
uword temp = seed[0] + seed[1] + seed[2]
seed[0] = seed[1]
seed[1] = seed[2]
seed[2] = temp
}
sub twist(uword x) -> uword {
ubyte xh = msb(x)
ubyte xl = lsb(x)
rol(xh)
rol(xl)
return mkword(xh, xl)
}
sub debug_seed() {
txt.print("\ngalaxy9 #")
txt.print_ub(number)
txt.print("\ngalaxy9 seed0=")
txt.print_uwhex(galaxy9.seed[0], true)
txt.print("\ngalaxy9 seed1=")
txt.print_uwhex(galaxy9.seed[1], true)
txt.print("\ngalaxy9 seed2=")
txt.print_uwhex(galaxy9.seed[2], true)
txt.nl()
}
}
planet9 {
%option force_output
str[] species_sizes = ["Large", "Fierce", "Small"]
str[] species_colors = ["Green", "Red", "Yellow", "Blue", "Black", "Harmless"]
str[] species_looks = ["Slimy", "Bug-Eyed", "Horned", "Bony", "Fat", "Furry"]
str[] species_kinds = ["Rodents", "Frogs", "Lizards", "Lobsters", "Birds", "Humanoids", "Felines", "Insects"]
str[] govnames = ["Anarchy", "Feudal", "Multi-gov", "Dictatorship9", "Communist", "Confederacy", "Democracy", "Corporate State"]
str[] econnames = ["Rich Industrial", "Average Industrial", "Poor Industrial", "Mainly Industrial",
"Mainly Agricultural", "Rich Agricultural", "Average Agricultural", "Poor Agricultural"]
str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
str[] words82 = ["very", "mildly", "most", "reasonably", ""]
str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
str[] words8F = ["\xB0", "The planet9 \xB0", "The world \xB0", "This planet9", "This world"]
str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
str[] words91 = ["planet9", "world", "place", "little planet9", "dump"]
str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
uword[] wordlists = [
words81, words82, words83, words84, words85, words86, words87, words88,
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
words91, words92, words93, words94, words95, words96, words97, words98,
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
wordsA1, wordsA2, wordsA3, wordsA4]
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
str name = " " ; 8 max
ubyte number ; starts at 0 in new galaxy9, then increases by 1 for each generated planet9
ubyte x
ubyte y
ubyte economy
ubyte govtype
ubyte techlevel
ubyte population
uword productivity
uword radius
ubyte species_is_alien ; otherwise "Human Colonials"
ubyte species_size
ubyte species_color
ubyte species_look
ubyte species_kind
sub set_seed(uword s1, uword s2) {
goatsoup_seed[0] = lsb(s1)
goatsoup_seed[1] = msb(s1)
goatsoup_seed[2] = lsb(s2)
goatsoup_seed[3] = msb(s2)
reset_rnd()
}
sub reset_rnd() {
goatsoup_rnd[0] = goatsoup_seed[0]
goatsoup_rnd[1] = goatsoup_seed[1]
goatsoup_rnd[2] = goatsoup_seed[2]
goatsoup_rnd[3] = goatsoup_seed[3]
}
sub random_name() -> str {
ubyte ii
str name = " " ; 8 chars max
ubyte nx = 0
for ii in 0 to goatsoup_rnd_number() & 3 {
ubyte x = goatsoup_rnd_number() & $3e
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
x++
if pairs0[x] != '.' {
name[nx] = pairs0[x]
nx++
}
}
name[nx] = 0
name[0] |= 32 ; uppercase first letter
return name
}
sub goatsoup_rnd_number() -> ubyte {
ubyte x = goatsoup_rnd[0] * 2
uword a = x as uword + goatsoup_rnd[2]
if goatsoup_rnd[0] > 127
a ++
goatsoup_rnd[0] = lsb(a)
goatsoup_rnd[2] = x
x = goatsoup_rnd[1]
ubyte ac = x + goatsoup_rnd[3] + msb(a)
goatsoup_rnd[1] = ac
goatsoup_rnd[3] = x
return ac
}
sub distance(ubyte px, ubyte py) -> ubyte {
uword ax
uword ay
if px>x
ax=px-x
else
ax=x-px
if py>y
ay=py-y
else
ay=y-py
ay /= 2
ubyte d = sqrt16(ax*ax + ay*ay)
if d>63
return 255
return d*4
}
sub soup() -> str {
str planet9_result = " " * 160
uword[6] source_stack
ubyte stack_ptr = 0
str start_source = "\x8F is \x97."
uword source_ptr = &start_source
uword result_ptr = &planet9_result
reset_rnd()
recursive_soup()
return planet9_result
sub recursive_soup() {
repeat {
ubyte c = @(source_ptr)
source_ptr++
if c == $00 {
@(result_ptr) = 0
return
}
else if c <= $80 {
@(result_ptr) = c
result_ptr++
}
else {
if c <= $a4 {
ubyte rnr = goatsoup_rnd_number()
ubyte wordNr = (rnr >= $33) + (rnr >= $66) + (rnr >= $99) + (rnr >= $CC)
source_stack[stack_ptr] = source_ptr
stack_ptr++
source_ptr = getword(c, wordNr)
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
stack_ptr--
source_ptr = source_stack[stack_ptr]
} else {
if c == $b0 {
@(result_ptr) = name[0] | 32
result_ptr++
concat_string(&name + 1)
}
else if c == $b1 {
@(result_ptr) = name[0] | 32
result_ptr++
ubyte ni
for ni in 1 to len(name) {
ubyte cc = name[ni]
if cc=='e' or cc=='o' or cc==0
break
else {
@(result_ptr) = cc
result_ptr++
}
}
@(result_ptr) = 'i'
result_ptr++
@(result_ptr) = 'a'
result_ptr++
@(result_ptr) = 'n'
result_ptr++
}
else if c == $b2 {
concat_string(random_name())
}
else {
@(result_ptr) = c
result_ptr++
}
}
}
}
}
sub concat_string(uword str_ptr) {
repeat {
ubyte c = @(str_ptr)
if c==0
break
else {
@(result_ptr) = c
str_ptr++
result_ptr++
}
}
}
}
sub display(ubyte compressed) {
if compressed {
print_name_uppercase()
txt.print(" TL:")
txt.print_ub(techlevel+1)
txt.spc()
txt.print(econnames[economy])
txt.spc()
txt.print(govnames[govtype])
} else {
txt.print("\n\nSystem: ")
print_name_uppercase()
txt.print("\nPosition: ")
txt.print_ub(x)
txt.chrout('\'')
txt.print_ub(y)
txt.spc()
txt.chrout('#')
txt.print_ub(number)
txt.print("\nEconomy: ")
txt.print(econnames[economy])
txt.print("\nGovernment: ")
txt.print(govnames[govtype])
txt.print("\nTech Level: ")
txt.print_ub(techlevel+1)
txt.print("\nTurnover: ")
txt.print_uw(productivity)
txt.print("\nRadius: ")
txt.print_uw(radius)
txt.print("\nPopulation: ")
txt.print_ub(population >> 3)
txt.print(" Billion\nSpecies: ")
if species_is_alien {
if species_size < len(species_sizes) {
txt.print(species_sizes[species_size])
txt.spc()
}
if species_color < len(species_colors) {
txt.print(species_colors[species_color])
txt.spc()
}
if species_look < len(species_looks) {
txt.print(species_looks[species_look])
txt.spc()
}
if species_kind < len(species_kinds) {
txt.print(species_kinds[species_kind])
}
} else {
txt.print("Human Colonials")
}
txt.nl()
txt.print(soup())
txt.nl()
}
}
sub print_name_uppercase() {
ubyte c
for c in name
txt.chrout(c | 32)
}
asmsub getword(ubyte list @A, ubyte wordidx @Y) -> uword @AY {
%asm {{
sty P8ZP_SCRATCH_REG
sec
sbc #$81
asl a
tay
lda wordlists,y
sta P8ZP_SCRATCH_W1
lda wordlists+1,y
sta P8ZP_SCRATCH_W1+1
lda P8ZP_SCRATCH_REG
asl a
tay
lda (P8ZP_SCRATCH_W1),y
pha
iny
lda (P8ZP_SCRATCH_W1),y
tay
pla
rts
}}
}
}
util9 {
sub prefix_matches(uword prefixptr, uword stringptr) -> ubyte {
repeat {
ubyte pc = @(prefixptr)
ubyte sc = @(stringptr)
if pc == 0
return true
; to lowercase for case insensitive compare:
pc &= 127
sc &= 127
if pc != sc
return false
prefixptr++
stringptr++
}
return false
}
sub print_right(ubyte width, uword st) {
repeat width - string.length(st) {
txt.spc()
}
txt.print(st)
}
asmsub print_10s(uword value @AY) clobbers(A, X, Y) {
%asm {{
jsr conv.uword2decimal
lda conv.uword2decimal.decTenThousands
ldy #0 ; have we started printing?
cmp #'0'
beq +
jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decThousands
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decHundreds
cmp #'0'
bne +
cpy #0
beq ++
+ jsr c64.CHROUT
iny
+ lda conv.uword2decimal.decTens
jsr c64.CHROUT
lda #'.'
jsr c64.CHROUT
lda conv.uword2decimal.decOnes
jsr c64.CHROUT
rts
}}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -86,23 +86,11 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
DataType.ARRAY_UW -> "uword["
DataType.ARRAY_W -> "word["
DataType.ARRAY_F -> "float["
DataType.STRUCT -> "" // the name of the struct is enough
DataType.STRUCT -> "" // TODO STRUCT DOESN'T EXIST ANYMORE
else -> "?????"
}
}
override fun visit(structDecl: StructDecl) {
outputln("struct ${structDecl.name} {")
scopelevel++
for(decl in structDecl.statements) {
outputi("")
decl.accept(this)
output("\n")
}
scopelevel--
outputlni("}")
}
override fun visit(decl: VarDecl) {
// if the vardecl is a parameter of a subroutine, don't output it again
@ -116,9 +104,6 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
VarDeclType.MEMORY -> output("&")
}
if(decl.datatype==DataType.STRUCT && decl.struct!=null)
output(decl.struct!!.name)
output(datatypeString(decl.datatype))
if(decl.arraysize!=null) {
decl.arraysize!!.indexExpr.accept(this)

View File

@ -124,18 +124,7 @@ interface INameScope {
fun lookup(scopedName: List<String>, localContext: Node) : Statement? {
if(scopedName.size>1) {
// a scoped name can a) refer to a member of a struct, or b) refer to a name in another module.
// try the struct first.
val thing = lookup(scopedName.dropLast(1), localContext) as? VarDecl
val struct = thing?.struct
if (struct != null) {
if(struct.statements.any { (it as VarDecl).name == scopedName.last()}) {
// return ref to the mangled name variable
val mangled = mangledStructMemberName(thing.name, scopedName.last())
return thing.definingScope().getLabelOrVariable(mangled)
}
}
// a scoped name refers to a name in another module.
// it's a qualified name, look it up from the root of the module's namespace (consider all modules in the program)
for(module in localContext.definingModule().program.modules) {
var scope: INameScope? = module
@ -297,7 +286,7 @@ class Program(val name: String,
if(existing!=null)
return existing
val decl = VarDecl(VarDeclType.VAR, DataType.STR, ZeropageWish.NOT_IN_ZEROPAGE, null, "string_${internedStrings.size}", null, string,
val decl = VarDecl(VarDeclType.VAR, DataType.STR, ZeropageWish.NOT_IN_ZEROPAGE, null, "string_${internedStrings.size}", string,
isArray = false, autogeneratedDontRemove = true, position = string.position)
val internedStringsBlock = modules.first { it.name==internedStringsModuleName }.statements.first { it is Block && it.name == internedStringsModuleName}
(internedStringsBlock as Block).statements.add(decl)
@ -384,20 +373,6 @@ class GlobalNamespace(val modules: List<Module>, private val builtinFunctionName
return builtinPlaceholder
}
if(scopedName.size>1) {
// a scoped name can a) refer to a member of a struct, or b) refer to a name in another module.
// try the struct first.
val thing = lookup(scopedName.dropLast(1), localContext) as? VarDecl
val struct = thing?.struct
if (struct != null) {
if(struct.statements.any { (it as VarDecl).name == scopedName.last()}) {
// return ref to the mangled name variable
val mangled = mangledStructMemberName(thing.name, scopedName.last())
return thing.definingScope().getLabelOrVariable(mangled)
}
}
}
// special case: the do....until statement can also look INSIDE the anonymous scope
if(localContext.parent.parent is UntilLoop) {
val symbolFromInnerScope = (localContext.parent.parent as UntilLoop).body.lookup(scopedName, localContext)
@ -407,7 +382,7 @@ class GlobalNamespace(val modules: List<Module>, private val builtinFunctionName
// lookup something from the module.
return when (val stmt = localContext.definingModule().lookup(scopedName, localContext)) {
is Label, is VarDecl, is Block, is Subroutine, is StructDecl -> stmt
is Label, is VarDecl, is Block, is Subroutine -> stmt
null -> null
else -> throw SyntaxError("invalid identifier target type", stmt.position)
}
@ -423,10 +398,6 @@ object BuiltinFunctionScopePlaceholder : INameScope {
}
// prefix for struct member variables
fun mangledStructMemberName(varName: String, memberName: String) = "prog8struct_${varName}_$memberName"
fun Number.toHex(): String {
// 0..15 -> "0".."15"
// 16..255 -> "$10".."$ff"

View File

@ -66,7 +66,6 @@ private fun prog8Parser.VariabledeclarationContext.toAst(encoding: IStringEncodi
if (vd.ZEROPAGE() != null) ZeropageWish.PREFER_ZEROPAGE else ZeropageWish.DONTCARE,
vd.arrayindex()?.toAst(encoding),
vd.varname.text,
null,
it.expression().toAst(encoding),
vd.ARRAYSIG() != null || vd.arrayindex() != null,
false,
@ -74,37 +73,6 @@ private fun prog8Parser.VariabledeclarationContext.toAst(encoding: IStringEncodi
)
}
structvarinitializer()?.let {
val vd = it.structvardecl()
return VarDecl(
VarDeclType.VAR,
DataType.STRUCT,
ZeropageWish.NOT_IN_ZEROPAGE,
null,
vd.varname.text,
vd.structname.text,
it.expression().toAst(encoding),
isArray = false,
autogeneratedDontRemove = false,
position = it.toPosition()
)
}
structvardecl()?.let {
return VarDecl(
VarDeclType.VAR,
DataType.STRUCT,
ZeropageWish.NOT_IN_ZEROPAGE,
null,
it.varname.text,
it.structname.text,
null,
isArray = false,
autogeneratedDontRemove = false,
position = it.toPosition()
)
}
constdecl()?.let {
val cvarinit = it.varinitializer()
val vd = cvarinit.vardecl()
@ -114,7 +82,6 @@ private fun prog8Parser.VariabledeclarationContext.toAst(encoding: IStringEncodi
if (vd.ZEROPAGE() != null) ZeropageWish.PREFER_ZEROPAGE else ZeropageWish.DONTCARE,
vd.arrayindex()?.toAst(encoding),
vd.varname.text,
null,
cvarinit.expression().toAst(encoding),
vd.ARRAYSIG() != null || vd.arrayindex() != null,
false,
@ -131,7 +98,6 @@ private fun prog8Parser.VariabledeclarationContext.toAst(encoding: IStringEncodi
if (vd.ZEROPAGE() != null) ZeropageWish.PREFER_ZEROPAGE else ZeropageWish.DONTCARE,
vd.arrayindex()?.toAst(encoding),
vd.varname.text,
null,
mvarinit.expression().toAst(encoding),
vd.ARRAYSIG() != null || vd.arrayindex() != null,
false,
@ -139,12 +105,6 @@ private fun prog8Parser.VariabledeclarationContext.toAst(encoding: IStringEncodi
)
}
structdecl()?.let {
return StructDecl(it.identifier().text,
it.vardecl().map { vd->vd.toAst(encoding) }.toMutableList(),
toPosition())
}
throw FatalAstException("weird variable decl $this")
}
@ -639,7 +599,6 @@ private fun prog8Parser.VardeclContext.toAst(encoding: IStringEncoding): VarDecl
arrayindex()?.toAst(encoding),
varname.text,
null,
null,
ARRAYSIG() != null || arrayindex() != null,
false,
toPosition()

View File

@ -786,27 +786,9 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
override fun inferType(program: Program): InferredTypes.InferredType {
return when (val targetStmt = targetStatement(program)) {
is VarDecl -> InferredTypes.knownFor(targetStmt.datatype)
is StructDecl -> InferredTypes.knownFor(DataType.STRUCT)
else -> InferredTypes.InferredType.unknown()
}
}
fun memberOfStruct(program: Program) = this.targetVarDecl(program)?.struct
fun firstStructVarName(program: Program): String? {
// take the name of the first struct member of the structvariable instead
// if it's just a regular variable, return null.
val struct = memberOfStruct(program) ?: return null
val decl = targetVarDecl(program)!!
if(decl.datatype!=DataType.STRUCT)
return null
val firstStructMember = struct.nameOfFirstMember()
// find the flattened var that belongs to this first struct member
val firstVarName = listOf(decl.name, firstStructMember)
val firstVar = definingScope().lookup(firstVarName, this) as VarDecl
return firstVar.name
}
}
class FunctionCall(override var target: IdentifierReference,

View File

@ -161,16 +161,11 @@ open class VarDecl(val type: VarDeclType,
val zeropage: ZeropageWish,
var arraysize: ArrayIndex?,
override val name: String,
private val structName: String?,
var value: Expression?,
val isArray: Boolean,
val autogeneratedDontRemove: Boolean,
override val position: Position) : Statement(), ISymbolStatement {
override lateinit var parent: Node
var struct: StructDecl? = null // set later (because at parse time, we only know the name)
private set
var structHasBeenFlattened = false // set later
private set
var allowInitializeWithZero = true
// prefix for literal values that are turned into a variable on the heap
@ -187,7 +182,7 @@ open class VarDecl(val type: VarDeclType,
array.type.typeOrElse(DataType.STRUCT)
val declaredType = ArrayElementTypes.getValue(arrayDt)
val arraysize = ArrayIndex.forArray(array)
return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, null, array,
return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, array,
isArray = true, autogeneratedDontRemove = true, position = array.position)
}
@ -221,16 +216,6 @@ open class VarDecl(val type: VarDeclType,
this.parent = parent
arraysize?.linkParents(this)
value?.linkParents(this)
if(structName!=null) {
val structStmt = definingScope().lookup(listOf(structName), this)
if(structStmt!=null) {
val node = definingScope().lookup(listOf(structName), this)
if(node is StructDecl)
struct = node
else
datatypeErrors.add(SyntaxError("invalid datatype declaration", position))
}
}
}
override fun replaceChildNode(node: Node, replacement: Node) {
@ -243,7 +228,7 @@ open class VarDecl(val type: VarDeclType,
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString(): String {
return "VarDecl(name=$name, vartype=$type, datatype=$datatype, struct=$structName, value=$value, pos=$position)"
return "VarDecl(name=$name, vartype=$type, datatype=$datatype, value=$value, pos=$position)"
}
fun zeroElementValue(): NumericLiteralValue {
@ -253,45 +238,16 @@ open class VarDecl(val type: VarDeclType,
throw IllegalArgumentException("attempt to get zero value for vardecl that shouldn't get it")
}
fun flattenStructMembers(): MutableList<Statement> {
val result = struct!!.statements.mapIndexed { index, statement ->
val member = statement as VarDecl
val initvalueOrig = if(value!=null) (value as ArrayLiteralValue).value[index] else null
val initvalue = when(initvalueOrig) {
is AddressOf -> initvalueOrig.copy()
is ArrayIndexedExpression -> initvalueOrig.copy()
is DirectMemoryRead -> initvalueOrig.copy()
is IdentifierReference -> initvalueOrig.copy()
else -> initvalueOrig
}
VarDecl(
VarDeclType.VAR,
member.datatype,
ZeropageWish.NOT_IN_ZEROPAGE,
member.arraysize,
mangledStructMemberName(name, member.name),
struct!!.name,
initvalue,
member.isArray,
true,
member.position
)
}.toMutableList<Statement>()
structHasBeenFlattened = true
return result
}
fun copy(): VarDecl {
val c = VarDecl(type, declaredDatatype, zeropage, arraysize, name, structName, value, isArray, autogeneratedDontRemove, position)
val c = VarDecl(type, declaredDatatype, zeropage, arraysize, name, value, isArray, autogeneratedDontRemove, position)
c.allowInitializeWithZero = this.allowInitializeWithZero
c.structHasBeenFlattened = this.structHasBeenFlattened
return c
}
}
// a vardecl used only for subroutine parameters
class ParameterVarDecl(name: String, declaredDatatype: DataType, position: Position)
: VarDecl(VarDeclType.VAR, declaredDatatype, ZeropageWish.DONTCARE, null, name, null, null, false, true, position)
: VarDecl(VarDeclType.VAR, declaredDatatype, ZeropageWish.DONTCARE, null, name, null, false, true, position)
class ArrayIndex(var indexExpr: Expression,
override val position: Position) : Node {
@ -955,36 +911,6 @@ class WhenChoice(var values: MutableList<Expression>?, // if null, th
fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
}
class StructDecl(override val name: String,
override var statements: MutableList<Statement>, // actually, only vardecls here
override val position: Position): Statement(), INameScope {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
this.statements.forEach { it.linkParents(this) }
}
override fun replaceChildNode(node: Node, replacement: Node) {
require(replacement is Statement)
val idx = statements.indexOfFirst { it===node }
statements[idx] = replacement
replacement.parent = this
}
val numberOfElements: Int
get() = this.statements.size
fun memsize(memsizer: IMemSizer) =
statements.map { memsizer.memorySize((it as VarDecl).datatype) }.sum()
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
fun nameOfFirstMember() = (statements.first() as VarDecl).name
}
class DirectMemoryWrite(var addressExpression: Expression, override val position: Position) : Node {
override lateinit var parent: Node

View File

@ -111,7 +111,6 @@ abstract class AstWalker {
open fun before(returnStmt: Return, parent: Node): Iterable<IAstModification> = noModifications
open fun before(scope: AnonymousScope, parent: Node): Iterable<IAstModification> = noModifications
open fun before(string: StringLiteralValue, parent: Node): Iterable<IAstModification> = noModifications
open fun before(structDecl: StructDecl, parent: Node): Iterable<IAstModification> = noModifications
open fun before(subroutine: Subroutine, parent: Node): Iterable<IAstModification> = noModifications
open fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> = noModifications
open fun before(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> = noModifications
@ -152,7 +151,6 @@ abstract class AstWalker {
open fun after(returnStmt: Return, parent: Node): Iterable<IAstModification> = noModifications
open fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> = noModifications
open fun after(string: StringLiteralValue, parent: Node): Iterable<IAstModification> = noModifications
open fun after(structDecl: StructDecl, parent: Node): Iterable<IAstModification> = noModifications
open fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> = noModifications
open fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> = noModifications
open fun after(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> = noModifications
@ -235,7 +233,6 @@ abstract class AstWalker {
track(before(decl, parent), decl, parent)
decl.value?.accept(this, decl)
decl.arraysize?.accept(this, decl)
decl.struct?.accept(this, decl)
track(after(decl, parent), decl, parent)
}
@ -435,11 +432,5 @@ abstract class AstWalker {
whenChoice.statements.accept(this, whenChoice)
track(after(whenChoice, parent), whenChoice, parent)
}
fun visit(structDecl: StructDecl, parent: Node) {
track(before(structDecl, parent), structDecl, parent)
structDecl.statements.forEach { it.accept(this, structDecl) }
track(after(structDecl, parent), structDecl, parent)
}
}

View File

@ -33,7 +33,6 @@ interface IAstVisitor {
fun visit(decl: VarDecl) {
decl.value?.accept(this)
decl.arraysize?.accept(this)
decl.struct?.accept(this)
}
fun visit(subroutine: Subroutine) {
@ -170,8 +169,4 @@ interface IAstVisitor {
whenChoice.values?.forEach { it.accept(this) }
whenChoice.statements.accept(this)
}
fun visit(structDecl: StructDecl) {
structDecl.statements.forEach { it.accept(this) }
}
}

View File

@ -330,39 +330,6 @@ read the syntax reference on strings.
The same is true for arrays! So be careful to (re)initialize them if needed.
Structs
^^^^^^^
A struct is a group of one or more other variables.
This allows you to reuse the definition and manipulate it as a whole.
Individual variables in the struct are accessed as you would expect, just
use a scoped name to refer to them: ``structvariable.membername``.
Structs are a bit limited in Prog8: you can only use numerical variables
as member of a struct, so strings and arrays and other structs can not be part of a struct.
Also, it is not possible to use a struct itself inside an array.
Structs are mainly syntactic sugar for repeated groups of vardecls
and assignments that belong together. However,
*they are layed out in sequence in memory as the members are defined*
which may be usefulif you want to pass pointers around.
To create a variable of a struct type you need to define the struct itself,
and then create a variable with it::
struct Color {
ubyte red
ubyte green
ubyte blue
}
Color rgb = [255,122,0] ; note that struct initializer value is same as an array
Color another ; the init value is optional, like arrays
another = rgb ; assign all of the values of rgb to another
another.blue = 255 ; set a single member
Special types: const and memory-mapped
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -875,11 +842,6 @@ sizeof(name)
For an 10 element array of floats, it is 50 (on the C-64, where a float is 5 bytes).
Note: usually you will be interested in the number of elements in an array, use len() for that.
offsetof(membername)
Number of bytes from the start of a struct variable that this member variable is located.
For now, this only works on members of a declared struct variable and not yet on members
referenced from the struct type itself. This might be improved in a future version of the language.
swap(x, y)
Swap the values of numerical variables (or memory locations) x and y in a fast way.

View File

@ -253,7 +253,6 @@ Various examples::
byte[5] values = 255 ; initialize with five 255 bytes
word @zp zpword = 9999 ; prioritize this when selecting vars for zeropage storage
Color rgb = {1,255,0} ; a struct variable with initial values
Data types
@ -387,27 +386,6 @@ Syntax is familiar with brackets: ``arrayvar[x]`` ::
string[4] ; the fifth character (=byte) in the string
Struct
^^^^^^
A *struct* has to be defined to specify what its member variables are.
There are one or more members::
struct <structname> {
<vardecl>
[ <vardecl> ...]
}
You can only use numerical variables as member of a struct, so strings and arrays
and other structs can not be part of a struct. Vice versa, a struct can not occur in an array.
After defining a struct you can use the name of the struct as a data type to declare variables with.
Struct variables can be assigned a struct literal value (also in their declaration as initial value)::
Color rgb = [255, 100, 0] ; note that the value is an array
String
^^^^^^

View File

@ -2,8 +2,12 @@
TODO
====
- get rid of Datatype.STRUCT
- fix problem that unused vars are no longer properly removed
- BeforeAsmGenerationAstChanger no longer needs to move vardecls??
- simplify cx16.joystick_get2() once this cx16 rom issue is resolved: https://github.com/commanderx16/x16-rom/issues/203
- hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine)
- c64: make the graphics.BITMAP_ADDRESS configurable (VIC banking)
- get rid of all other TODO's in the code ;-)

View File

@ -6,21 +6,17 @@
main {
struct Ball {
float t
ubyte color
}
sub start() {
Ball ball
float ball_t
ubyte ball_color
repeat {
ubyte xx=(sin(ball.t) * txt.DEFAULT_WIDTH/2.1) + txt.DEFAULT_WIDTH/2.0 as ubyte
ubyte yy=(cos(ball.t*1.1356) * txt.DEFAULT_HEIGHT/2.1) + txt.DEFAULT_HEIGHT/2.0 as ubyte
txt.setcc(xx, yy, 81, ball.color)
ball.t += 0.08
ball.color++
ubyte xx=(sin(ball_t) * txt.DEFAULT_WIDTH/2.1) + txt.DEFAULT_WIDTH/2.0 as ubyte
ubyte yy=(cos(ball_t*1.1356) * txt.DEFAULT_HEIGHT/2.1) + txt.DEFAULT_HEIGHT/2.0 as ubyte
txt.setcc(xx, yy, 81, ball_color)
ball_t += 0.08
ball_color++
}
}
}

View File

@ -6,21 +6,18 @@
main {
const uword screenwidth = txt.DEFAULT_WIDTH
const uword screenheight = txt.DEFAULT_HEIGHT
struct Ball {
uword anglex
uword angley
ubyte color
}
uword anglex
uword angley
ubyte color
sub start() {
Ball ball
repeat {
ubyte x = msb(sin8u(msb(ball.anglex)) * screenwidth)
ubyte y = msb(cos8u(msb(ball.angley)) * screenheight)
txt.setcc(x, y, 81, ball.color)
ball.anglex+=366
ball.angley+=291
ball.color++
ubyte x = msb(sin8u(msb(anglex)) * screenwidth)
ubyte y = msb(cos8u(msb(angley)) * screenheight)
txt.setcc(x, y, 81, color)
anglex+=366
angley+=291
color++
}
}
}

View File

@ -1,29 +1,26 @@
%import conv
%import gfx2
%import textio
main {
sub start() {
gfx2.screen_mode(6) ; highres 4c
gfx2.text_charset(3)
gfx2.text(10, 10, 1, @"Hello!")
c64.SETTIM(0,0,0)
; TODO WHY AREN'T UNUSED VARS REMOVED ANY LONGER???
ubyte rr
for rr in 0 to 2 {
uword yy
for yy in 20 to 420 {
gfx2.horizontal_line(10, yy, 610, (lsb(yy>>3) + rr) & 3)
}
}
uword time = c64.RDTIM16()
conv.str_uw(time)
gfx2.text(100, 10, 1, conv.string_out)
ubyte xx1
ubyte yy1=22
ubyte zz1=33
repeat {
ubyte xx
ubyte yy=xx
ubyte aa
ubyte bb
ubyte cc
ubyte dd
}
repeat {
xx=1
yy=xx
}
}
}

View File

@ -74,31 +74,14 @@ trader {
str input = "??????????"
ubyte num_chars
struct SaveData {
ubyte galaxy
ubyte planet
ubyte cargo0
ubyte cargo1
ubyte cargo2
ubyte cargo3
ubyte cargo4
ubyte cargo5
ubyte cargo6
ubyte cargo7
ubyte cargo8
ubyte cargo9
ubyte cargo10
ubyte cargo11
ubyte cargo12
ubyte cargo13
ubyte cargo14
ubyte cargo15
ubyte cargo16
uword cash
ubyte max_cargo
ubyte fuel
}
SaveData savedata
ubyte[23] savedata
; format:
; 0 ubyte galaxy
; 1 ubyte planet
; 2-18 ubyte cargo0..cargo16
; 19 uword cash
; 21 ubyte max_cargo
; 22 ubyte fuel
sub do_load() {
txt.print("\nLoading universe...")
@ -111,22 +94,23 @@ trader {
return
}
ship.cash = savedata.cash
ship.Max_cargo = savedata.max_cargo
ship.fuel = savedata.fuel
sys.memcopy(&savedata.cargo0, ship.cargohold, len(ship.cargohold))
galaxy.travel_to(savedata.galaxy, savedata.planet)
ship.cash = mkword(savedata[20], savedata[19])
ship.Max_cargo = savedata[21]
ship.fuel = savedata[22]
sys.memcopy(&savedata + 2, ship.cargohold, len(ship.cargohold))
galaxy.travel_to(savedata[0], savedata[1])
planet.display(false, 0)
}
sub do_save() {
savedata.galaxy = galaxy.number
savedata.planet = planet.number
savedata.cash = ship.cash
savedata.max_cargo = ship.Max_cargo
savedata.fuel = ship.fuel
sys.memcopy(ship.cargohold, &savedata.cargo0, len(ship.cargohold))
savedata[0] = galaxy.number
savedata[1] = planet.number
savedata[19] = lsb(ship.cash)
savedata[20] = msb(ship.cash)
savedata[21] = ship.Max_cargo
savedata[22] = ship.fuel
sys.memcopy(ship.cargohold, &savedata + 2, len(ship.cargohold))
txt.print("\nSaving universe...")
diskio.delete(8, Savegame)

View File

@ -109,12 +109,9 @@ statement :
variabledeclaration :
varinitializer
| structvarinitializer
| vardecl
| structvardecl
| constdecl
| memoryvardecl
| structdecl
;
@ -139,18 +136,12 @@ directivearg : stringliteral | identifier | integerliteral ;
vardecl: datatype ZEROPAGE? (arrayindex | ARRAYSIG) ? varname=identifier ;
structvardecl: structname=identifier varname=identifier ;
varinitializer : vardecl '=' expression ;
structvarinitializer : structvardecl '=' expression ;
constdecl: 'const' varinitializer ;
memoryvardecl: ADDRESS_OF varinitializer;
structdecl: 'struct' identifier '{' EOL vardecl ( EOL vardecl)* EOL? '}' EOL;
datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'float' | 'str' ;
arrayindex: '[' expression ']' ;

View File

@ -13,8 +13,8 @@
</options>
<keywords keywords="&amp;;-&gt;;@;\$;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;until;when;while;xor;~" ignore_case="false" />
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%launcher;%option;%output;%target;%zeropage;%zpreserved" />
<keywords3 keywords="byte;const;float;str;struct;ubyte;uword;void;word;zp" />
<keywords4 keywords="abs;acos;all;any;asin;atan;avg;callfar;callrom;ceil;cmp;cos;cos16;cos16u;cos8;cos8u;deg;floor;len;ln;log2;lsb;lsl;lsr;max;memory;min;mkword;msb;offsetof;peek;peekw;poke;pokew;rad;reverse;rnd;rndf;rndw;rol;rol2;ror;ror2;round;sgn;sin;sin16;sin16u;sin8;sin8u;sizeof;sort;sqrt;sqrt16;sum;swap;tan" />
<keywords3 keywords="byte;const;float;str;ubyte;uword;void;word;zp" />
<keywords4 keywords="abs;acos;all;any;asin;atan;avg;callfar;callrom;ceil;cmp;cos;cos16;cos16u;cos8;cos8u;deg;floor;len;ln;log2;lsb;lsl;lsr;max;memory;min;mkword;msb;peek;peekw;poke;pokew;rad;reverse;rnd;rndf;rndw;rol;rol2;ror;ror2;round;sgn;sin;sin16;sin16u;sin8;sin8u;sizeof;sort;sqrt;sqrt16;sum;swap;tan" />
</highlighting>
<extensionMap>
<mapping ext="p8" />

View File

@ -44,7 +44,6 @@ syn region prog8ArrayType matchgroup=prog8Type
\ transparent
syn keyword prog8StorageClass const
syn match prog8StorageClass "\(^\|\s\)@zp\>"
syn keyword prog8Structure struct
syn region prog8Block start="{" end="}" transparent
syn region prog8Expression start="(" end=")" transparent

View File

@ -16,7 +16,7 @@ syn keyword prog8BuiltInFunc any all len max min reverse sum sort
" Miscellaneous functions
syn keyword prog8BuiltInFunc cmp lsb msb mkword peek peekw poke pokew rnd rndw
syn keyword prog8BuiltInFunc rndf rol rol2 ror ror2 sizeof offsetof
syn keyword prog8BuiltInFunc rndf rol rol2 ror ror2 sizeof
syn keyword prog8BuiltInFunc swap memory callfar callrom